2011-08-31 43 views
10

今天我偶然發現了一些有趣的東西。 假設下面的Java 6類:覆蓋使用類型擦除的方法

public class Ereasure { 

    public Object get(Object o) { 
     return null; // dummy 
    } 

    public static class Derived<T> extends Ereasure{ 
     // (1) 
     @Override 
     public Object get(T o) { 
       return super.get(o); 
     } 
     // (2) 
     /* 
     @Override 
     public Object get(Object o) { 
       return super.get(o); 
     }*/ 

    } 
} 

如果你試圖編譯上面的例子中,編譯器說 Ereasure.java:9:方法不覆蓋或從超 實現的方法@Override 如果你刪除了@Override註解(這不應該是必要的!),它說 Ereasure.java:8:名稱衝突:Ereasure.Derived中的get(T)和Ereasure中的get(java.lang.Object)具有相同的擦除,但是兩者都不會覆蓋其他 這有點矛盾,因爲T應該複製到Object並因此覆蓋父類get方法。如果你離開(1)unannotated和取消註釋(2)so(1)重載(2)它也不起作用。 編譯器輸出:

Ereasure.java:15: get(T) is already defined in Ereasure.Derived 
    public Object get(Object o) { 

作爲結論,T正在ereased反對意見,但不能覆蓋父get方法。

我現在的問題是,爲什麼dooesn至少有一個例子編譯?

+0

@ toto2我認爲你的權利,但我也認爲它是一個有趣的看似無證的角落案件。根據Sun編譯器關於Type Erasure的說明,Derived中的方法定義應將Derived的get中的無界類型轉換爲public Object get(Object o),因爲它的父級的子簽名應該覆蓋它。我認爲他是正確的,當把這個東西變成字節碼來解決無界類型導致的方法調度模糊時,沒有辦法。 – nsfyn55

回答

2

在一個簡單的猜測中,編譯器在計算重載時不使用通用視圖,這當然是沒有意義的,因爲有時T可能是Object而其他類型是其他類型。如果有多個方法都被稱爲「get」,但具有不同的單一參數類型,那麼重寫將會變得依賴於移動的目標T,這是完全錯誤的。在這種情況下,它只是沒有意義,而且他們猜測他們選擇的只是保持簡單。

+0

但是一般來說,每個泛型都是一個對象,因爲每個Java類都是從Object派生而來的...... – user3001

+0

不完全相同,在上面的T的下界是Object,其他的聲明miht通常使用不同的下界。 –

7

您可以在下面,爲什麼它是不可能做你想要什麼看到的例子:

public class Erasure { 

    public void set(Object o) { 
     return; 
    } 

    // method overloading: (which is valid) 
    public void set(String s) { 
     return; 
    } 

    public static class Derived<S> extends Erasure { 

     // Oops... which one am I supposed to override? 
     // (It would actually be overloading if S was a concrete type 
     // that is neither Object nor String.) 
     @Override 
     public void set(S o) { // does not compile 
     super.set(o); 
     } 
    } 
} 

你的問題的解決方案是,Erasure應該是一個參數化類。

1

考慮一種情況,即您將getter和setter重寫爲泛型。

Derived<String> d = new Derived<String(); 
Erasure e = d; 
e.set(new Object()); 
String s = d.get(); //Class cast exception 

泛型的基本原理是類轉換異常只有在(a)顯式轉換或(b)警告時纔會發生。如果你被允許做你想做的事,那麼上面沒有任何一個會拋出異常。