2014-05-16 35 views
1

如果我有一個泛型類,編譯器是否爲我使用的每種類型創建了一個不同的類?我們來考慮這個Class<T>。如果我創建了兩個類型爲Class<Integer>Class<String>的實例,編譯器是否會創建兩個不同的類?當使用泛型時,javac編譯器是否爲每種類型創建不同的類?

如果答案是否定的:如何擴展泛型類的類可以繼承相同的方法或具有不同類型的屬性(來自單個類)。

另一個問題:爲什麼我不能使用參數化類型檢查var instanceof Class<Integer>而不是ClassClass<?>

如果我嘗試這樣做,我得到以下錯誤:「無法執行instanceof檢查對參數化類型Test<Integer>使用形式Test<?>替代,因爲進一步的泛型類型信息將在運行時被刪除」

你能給我更多關於泛型的信息?

+2

簡短的答案是否。類型參數就是這樣的參數。 – Cruncher

+0

查找類型刪除。 –

+0

不,這就是爲什麼你實際上不能確定在很多情況下在哪個時間使用哪種通用類型的原因。這是一個編譯時間功能。 –

回答

11

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()的這種橋接方法。請注意橋接方法如何使用類型轉換來強制執行TString的綁定。這提供了一種擦除型世界中的安全措施。它確保下面產生一個異常:上述

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>,作爲通用的超類型信息被保持在元數據中。

0

不,只有一個類,因爲參數化類型只在運行時已知,編譯器無法爲每個匹配類型創建類。

當您擴展泛型類時,方法和成員將被繼承。我不明白你的目的... 例如:

public class MyClass<T> extends AbstractMyClass<T> { 

    @Override 
    public void add(T element) { 
     // do something with element... 
    } 


} 

    public class MyClass<T> { 
     private final List<T> store = new ArrayList<T>(); 

     protected void add(T element) { 
      store.add(element); 
     } 
    } 

[編輯]好吧,我想我不明白你的問題有關延長第一次...對不起[/編輯]

而且您無法檢查instanceof,因爲參數化類型在運行時未知。 你可以嘗試類似這樣的東西:how to instanceof List<MyType>?來檢查你的參數化類型是否相同。

相關問題