我有一個集合類型:如何將繼承對象的列表轉換爲Java中的對象集合?
Collection<A> collecA
而且我已經在我的對象列表:
List<B> listB
其中B是延伸的
class B extends A { ... }
但我不能請執行以下操作:
collecA = listB
我不明白爲什麼集合是由List實現的。
我有一個集合類型:如何將繼承對象的列表轉換爲Java中的對象集合?
Collection<A> collecA
而且我已經在我的對象列表:
List<B> listB
其中B是延伸的
class B extends A { ... }
但我不能請執行以下操作:
collecA = listB
我不明白爲什麼集合是由List實現的。
讓我們假設一個時刻,你可以做你的描述:
class B extends A { ... }
Collection<A> collecA;
List<B> listB;
collecA = listB; // normally an error, but lets pretend its allowed
collecA.add(new A()); // PROBLEM!
因爲collecA
是一家集 持有A
S中的方法調用collecA.add(new A())
似乎還好。但是,如果上述任務被允許,那麼我們有 的問題,因爲collecA
實際上是參考List<B>
實例 - 我只是 添加一個A
到只能容納B
s!
提問者還表示:
我不明白爲什麼,因爲收藏是通過列表來實現。
集合是List的超類無關緊要。即使您使用了兩個列表,此分配也是非法的。
class B extends A { ... }
List<A> listA;
List<B> listB;
listA = listB; // still an error, still leads to the same problem
的關鍵是,在List<A>
可變只能引用List
s表示可容納A
秒。但是,實例不能容納A
s。因此,List<A>
變量如listA
不能被指定爲參考listB
所指的List<B>
實例。
或者更一般地講:B
是的A
一個子類做了不暗示SomeGenericClass<B>
是SomeGenericClass<A>
(JLS §4.10的子類:亞型不通過泛型類型延伸:T <: U
並不意味着C<T> <: C<U>
。 )
這是從Java泛型教程這個例子/類比,幫助我理解這一點:
http://java.sun.com/docs/books/tutorial/java/generics/subtyping.html
「理解爲什麼變得容易得多,如果你認爲有形物體的 - 東西,你可以真正的圖片 - 如鳥籠,
// A cage is a collection of things, with bars to keep them in.
interface Cage<E> extends Collection<E>;
...
Cage<Lion> lionCage = ...;
Cage<Butterfly> butterflyCage = ...;
但是「動物籠子」呢?英語是模糊的,所以要精確假設我們正在談論的「所有的動物籠」:
Cage<Animal> animalCage = ...;
這是設計容納各種動物,混合在一起的籠子。它必須有足夠堅固的酒吧,以保持在獅子,足夠的間隔,以保持在蝴蝶。
...
由於獅子是一種動物(獅子是動物的一種亞型),問題就變成了:「獅子籠是一種動物籠子嗎?是Cage<Lion>
是Cage<Animal>
的子類型嗎?」。通過動物籠的上述定義,答案必須是「否」。這是令人驚訝的!但是當你考慮它時,它是完全有意義的:一個獅子籠不能被假定爲保持在蝴蝶中,並且一個蝴蝶籠不能被假定爲擁有獅子。因此,無論籠可考慮「所有動物」鳥籠。
animalCage = lionCage; // compile-time error
animalCage = butterflyCage; // compile-time error
「
Java泛型不是covariant。
查看Java Theory and Practice: Generics Gotchas瞭解更多詳情。
的頁面顯示了一個簡單的例子,將嚴重破壞類型系統,如果它是協:
想象一下,你可以一個列表<整數>分配給一個列表<號碼>。然後將下面的代碼將讓你把東西,是不是一個Integer放入名單<整數>:
List<Integer> li = new ArrayList<Integer>();
List<Number> ln = li; // illegal
ln.add(new Float(3.1415)); // ERROR: Adds a float to li, which is a list of Integers!
Collection<? extends A> collecA
這修復它。問題不是List extends Collection
,而是泛型類型。
您可以指定清單< B>收集< B>,但不是列表< B>收集< A>。
試想一下,如果這是可能會發生什麼:
List<B> = new ArrayList<B>();
Collection<A> collecA = listB; //Assume that this line compiles
collecA.add(new A());
B item = listB.get(0); //ClassCastException!
正如你看到的,我們「上當」的泛型類型的系統,通過增加具體類型的實例,這應該只是有一個集合類型B(或後代)的對象。 因此,對B執行隱式轉換的最後一行失敗,並帶有ClassCastException。它出什麼問題了?編譯器不能保證類型安全,這是違反Java泛型原則之一的。
因此,已決定列表< B>是類別< B>,而不是列出< A>(或集合< A>)。
作爲一個側面評論,有趣的是,數組並沒有遵循相同的規則:String [] 是一個Object [],並且賦值是合法的。
好易理解的解釋伯特我一直讚賞愚蠢試圖瞭解泛型和繼承類比時,應Kartoch檢查一下 – tgai 2010-05-02 21:34:35
@Tamon - 很高興你(希望其他人)發現它很容易理解,我對理解泛型和繼承有同樣的問題(更不用說通用通配符),所以它採用了一個新的例子,就像Java泛型教程在我的腦海中將它融入其中我搜索了'java generic cast animal cage'來記住我在哪裏閱讀這個比喻。:-) – 2010-05-02 22:16:41
確實很好的解釋... – Kartoch 2010-05-03 10:39:06