If I have a generic class, does the compiler create a different class for every type I use with it? Let's consider this Class. If I create two instances of type Class and Class, does the compiler create two different classes?
沒有,有一個單獨的類,並且在字節碼,類型變量的所有外觀與他們的上界(通常Object
被有效替代,但對形式的類型變量可能有一些類型爲U
)。這個概念被稱爲類型擦除,因爲類型變量實際上是擦除(並用其上限代替)。
If the answer is no: how it's possible that classes that extend a generic class can inherit the same method or attribute with a different type (from a single class).?
有趣的問題!假設您有兩個不同的類實現Comparator<T>
。一個實施Comparator<String>
,另一個實施Comparator<Integer>
。
Comparator<T>
定義了以下方法:
int compare(T p0, T p1)
那麼如何兩個不同一般的情況下實現具有不同的參數類型相同的方法?那麼,在代碼中實現的方法實際上並不會覆蓋Comparator.compare()
。 Comparer.compare()
接受兩個Object
參數,但Comparator<String>.compare()
接受兩個String
參數。他們不是一樣的方法。那麼,爲什麼它像重寫一樣表現爲?因爲編譯器會爲您生成一個隱藏的橋接方法。通過反編譯器或反彙編程序運行通用實現來親自查看。從我自己的Procyon反編譯運行下面的輸出與--show-synthetic
:
public enum StringComparator implements Comparator<String> {
ORDINAL {
@Override
public int compare(final String s1, final String s2) {
if (s1 == null) {
return (s2 == null) ? 0 : -1;
}
if (s2 == null) {
return 1;
}
return s1.compareTo(s2);
}
@Override
public /* bridge */ int compare(final Object x0, final Object x1) {
return this.compare((String)x0, (String)x1);
}
},
...
}
第compare()
方法是由StringComparator
類的作者寫的實際執行。第二種方法是隱藏的,並且由編譯器生成。它的存在是將通用實現與其「已擦除」定義「橋接」,並且這是實現接口方法Comparator.compare()
的這種橋接方法。請注意橋接方法如何使用類型轉換來強制執行T
到String
的綁定。這提供了一種擦除型世界中的安全措施。它確保下面產生一個異常:上述
class IntegerComparator implements Comparator<Integer> { ... }
// 'c' is a raw Comparator, or effectively a Comparator<Object>
// (note the lack of type arguments).
Comparator c = new IntegerComparator();
int result = c.compare(1, "hello");
代碼編譯細,因爲Comparator.compare()
的原始形式接受兩個Object
參數。但在運行時,該呼叫將觸發ClassCastException
,因爲IntegerComparator
中的網橋方法將嘗試將字符串「hello」投射到Integer
。
Another question: why can't I check var instanceof Class<Integer> using parameterized type instead of Class or Class<?>?
由於具體的泛型類型共享同一個類的所有實例,其中所有類型變量被擦除,一個通用類實例沒有超出其原始類型的認同感。它不知道它被實例化的類型參數,因爲這些信息在編譯期間已經被煮掉了。如果你實例化一個ArrayList<String>
,結果實例只知道它是一個ArrayList
。在這種情況下,instance instanceof ArrayList<String>
的檢查無法產生有意義的結果。由於這樣的檢查不能可靠地產生有意義的結果,所以它們是不允許的。
有趣的是,StringComparator
類的上述實例不知道它實現Comparator<String>
,作爲通用的超類型信息被保持在元數據中。
簡短的答案是否。類型參數就是這樣的參數。 – Cruncher
查找類型刪除。 –
不,這就是爲什麼你實際上不能確定在很多情況下在哪個時間使用哪種通用類型的原因。這是一個編譯時間功能。 –