2009-11-17 49 views
2

我嘗試寫一些代碼,看起來像這樣:Java是否有任何計劃添加通用收集協方差?

public List<IObject> getObject(){ 
    ArrayList<ConcreteObject> objects = new ArrayList<ConcreteObject>(); 
    return objects; 
} 

(其中ConcreteObject實現IObject提取)

這並不在所有的工作。它給出了一個編譯器錯誤。 Java是否有計劃在未來支持這一點?到那時爲止最好的解決方法是什麼?我最終做的是:

public List<IObject> getObject(){ 
    List<IObject> objects = new ArrayList<IObject>(); 
    return objects; 
} 

這個工作,也許沒有真的有這樣做的不良副作用。這是普遍接受的最佳方法嗎?

回答

11

的Java已經支持此功能,你只需要使用它。有關底漆,請閱讀Sun的Wildcards tutorial

你想要的是以下幾點:

public List<? extends IObject> getObject(){ 
    ArrayList<ConcreteObject> objects = new ArrayList<ConcreteObject>(); 
    return objects; 
} 

或者,可以使用不安全的轉換:

public <T extends IObject> List<T> getObject(){ 
    ArrayList<T> objects = (ArrayList<T>) new ArrayList<ConcreteObject>(); 
    return objects; 
} 

...但這種方法是比較脆,將拋出一個運行時異常(除信令編譯錯誤)當您嘗試訪問其無效類型的元素時:

@SuppressWarnings("unchecked") 
public <T extends IObject> List<T> getObject(){ 
    ArrayList<T> objects = (ArrayList<T>) new ArrayList<ConcreteObject>(); 
    objects.add(new ConcreteObject()); 
    return objects; 
} 

… 
List<OtherConcreteObject> objects = getObject(); // Works. 
OtherConcreteObject obj = OtherConcreteObject.get(0); // Throws CCE. 

這將導致在運行時的跟隨着ClassCastException:「ConcreteObject不能轉換爲OtherConcreteObject」 - 這是相當糟糕的,因爲如上面的代碼代表,它應該成功

出於這個原因,你應該儘量避免這種方法。

+0

你確定會編譯? ConcreteObject和IObject之間的連接在哪裏? – 2009-11-17 19:51:40

+2

啊,沒關係 - 我們假設它在ConcreteObject的定義中。 – 2009-11-17 19:52:27

+0

謝謝,我喜歡這種方法。 – 2009-11-17 20:11:17

5

這是採取一個例子,從那裏將它應用到你的情況Java Generics Tutorial

最好的說明的原因非法的:

List<ConcreteObject> concreteObjects = new ArrayList<ConcreteObject>(); 
List<IObject> objects = concreteObjects; // assume it's legal 
objects.add(new IObject() { // anonymous or some other (incompatible with ConcreteObject) implementation 
}); 
ConcreteObject co = concreteObjects.get(0); // Profit! er... I mean error 
+0

嗯,是的,我可以看到這將是一個問題。 – 2009-11-17 20:10:42

3

爲了支持協方差在您預期的方式,Java需要「具體化「泛型。一個通用的List<ConcreteObject>會知道它的元素需要是ConcreteObject的實例。因此,如果與該列表的引用呼叫者聲明爲List<IObject>試圖添加AnAlternateImplObject,該操作將在運行時失敗,異常—就像用數組類似的情況下,ArrayStoreException今天的罰球。

當時仿製藥中添加,沒有人能想出一個辦法來具體化類型不破壞現有代碼的兼容性。代之以提供使用通配符的「有界」泛型類型。然而,如果我沒有記錯的話,那麼從那時起就已經設計出一種兼容的物化方法,所以這個改變可能會回到遙遠的將來(Java 8?)。

在此期間,你使用的解決方案來處理這種情況下常規方式。

1

僅僅爲了興趣,如果你想用一種與Java相似的語言來處理真正的迂腐和嚴格的類型處理,你幾乎不可能比Scala做得更好。巴洛克式錯綜複雜的類型定義是斯卡拉的全部內容。教授Scala的作者Odersky是最初將泛型(更膽怯地)構建到Java中的人。