2011-09-16 40 views
1

我發現下面的代碼在Java中顯着:Java泛型,從C++模板來

ArrayList<String> l1 = new ArrayList<String>(); 
    ArrayList<Integer> l2 = new ArrayList<Integer>(); 
    System.out.println(l1.getClass() == l2.getClass()); // true 
    System.out.println(l2.getClass().isAssignableFrom(l1.getClass())); // true too 
    //ArrayList<Integer> l3 = l1; // won't compile though 

我不太明白的「isAssignableFrom」的細節。當然,我希望編譯器停止l3 = l2,但是它似乎與前一行相矛盾? (我確信這裏有微妙的一點,這就是我所追求的:-)

回答

8

所有的<Blah>信息在編譯時間後被剝離。就字節碼而言,它們都是同一類。

在編譯過程中,檢查它們的一致性和兼容性。

因此,當它執行l2.getClass().isAssignableFrom(l1.getClass())的檢查時,它說的是is ArrayList assignable from ArrayList?,答案是肯定的。但是因爲在編譯期間它仍然有類型信息,所以不允許。

+2

具體而言,這被稱爲*類型擦除*。關於泛型的Java教程很好的解釋了Java泛型的缺陷:http://download.oracle.com/javase/tutorial/java/generics/erasure.html – Scott

+0

是的,它感覺有點矛盾,因爲某些東西在運行時是正確的,但不是在編譯時,或者它是可分配的,但不能分配。它感覺不太對勁:-) – Frank

+0

@Frank我認爲依賴運行時正確性的思路是糟糕的設計;相反,我們應該設計我們的代碼,以便在編譯時捕獲錯誤。這並不是說我們總是成功:) – corsiKa

3

這是由Java的(相當sl))泛型實現引起的,即Type Erasure

基本上,編譯器會擦除類型信息(例如:ArrayList<String>ArrayList<Integer>都會變成ArrayList),並在必要時添加強制轉換。在運行時,l1l2之間沒有類型的區別,但編譯器不會讓你做任務 - 因爲知道類型是不同的。

0

isAssignableFrom()正在測試類是否相同,或者如果第二個類是第一個的超類或超接口。

正如其他答案所述,泛型在編譯期間被刪除,因此它們對該方法的輸出沒有影響。只有基類是mater。

參考:Class.isAssignableFrom()

+0

這是回到前面。它是第一個被測試作爲第二類的超類或超級界面的類。 – EJP

0

你想要什麼,本來由getType()方法提供服務,並l1.getType()應該返回ArrayList<String>l2.getType()應該返回ArrayList<Integer>

不幸的是,Java在Object上沒有getType()getClass()在兩種情況下都返回ArrayList

0

既然您發現l1.getClass() == l2.getClass()爲真,那麼l2.getClass().isAssignableFrom(l1.getClass())應該是顯而易見的(x.isAssignableFrom(x)應該始終爲true,否?)。你真正的問題是爲什麼l1.getClass() == l2.getClass()是真的,這是由於擦除。運行時只有一個類。