2013-10-03 90 views
0

有誰知道爲什麼是下列禁止:爲什麼不能將Collection <SomeType>轉換爲Java中的Collection <OtherType>?

Collection<SomeType> collection; 
Collection<OtherType> otherCollection = (Collection<OtherType>) collection; 

,同時允許以下:

Collection<SomeType> collection; 
Collection<OtherType> otherCollection = (Collection<OtherType>) (Collection<?>) collection; 

我已經用第二建築在我的程序之一。它解決了我所遇到的問題,但連續做兩個演員對我來說看起來很奇怪。

+0

我看不到這種方法中好的做法,會發生什麼,如果OTHERTYPE,在未來,從SOMETYPE相差這麼多呢?應用程序將停止工作。 – RamonBoza

+0

發生的事情與將SomeType轉換爲OtherType完全相同。你知道,在Java中允許投射。 –

+0

但是,這並不意味着,鑄造是一個很好的做法,如果同一層次的元素 – RamonBoza

回答

1

第一個是針對編譯器的語義,所以它不會編譯。但是在編譯時,泛型會被刪除,所以實際上您可以將任何想要的東西存儲到該集合中。

並且由於您通過第二個代碼段欺騙編譯器規則(通過強制轉換爲沒有泛型的集合),它將進行編譯。

+0

之間沒有做,爲什麼是第一個針對編譯語義? –

+2

@EtienneMiret因爲你告訴編譯器,蘋果是橙子,但是編譯器知道你在說謊。你應該修正你的泛型,而不是像這樣的黑客。給我們一個真實世界的例子,你需要做這樣的轉換,我們會告訴你如何正確地修復它。 – Kayaman

+0

我完全同意Kayaman。如果我有一個混合的集合,我不使用泛型,如果我有一個共同的超類,我可以在泛型中使用它。所以我也看不到像你的例子那樣的投射。 –

0

根據SCJP 6 Exam Book .-

在運行時,JVM不會知道一個集合的類型。所有 通用類型信息在編譯過程中被刪除,所以通過 時間到達JVM,根本沒有辦法識別將SomeType放入Collection<OtherType>中的這種 災難。

如果您嘗試投Collection<SomeType>Collection<OtherType>,編譯器會阻止你,因爲在運行時 的JVM就沒有辦法從加阻止你一個OtherType到 什麼作爲SomeType集合創建。

無論如何,假設有SomeTypeOtherType之間的遺產的關係,我猜你想要做像this.-

Collection<SomeType> collection = null; 
Collection<? extends OtherType> otherCollection = collection; 
1

禁止的東西,因爲它會破壞的目的泛型,即確保集合實際上包含其類型所指的內容。

一些例子。

Collection<String> strings = Arrays.asList("A", "B", "C"); 
// If this was allowed... 
Collection<Integer> integers = (Collection<Integer>) strings; 
// What would you expect from this? 
for (Integer i : integers) ... 

一個更微妙的情況是,在你而言,OtherTypeSomeType的超類型。

Collection<Integer> integers = Arrays.asList(1, 2, 3); 
// Shouldn't this be legal? Integer extends Number after all? 
Collection<Numbers> numbers = integers; 
// I might do this then 
numbers.add(2.0); 
// Ouch! integers now contains a Double. 
for (Integer i : integers) ... 

根據不同的情況,你可以使用關鍵字extends你的優勢。在extendssuper關鍵字

Collection<Integer> integers = Arrays.asList(1, 2, 3); 
// This IS legal 
Collection<? extends Numbers> numbers = integers; 
// This however does not compile: you cannot add anything to the Collection 
numbers.add(2.0); 

更多信息:What is PECS (Producer Extends Consumer Super)?

1

假設下面的語句的工作:

Collection<SomeType> collection; 
Collection<OtherType> otherCollection = (Collection<OtherType>) collection; //illegal 

這將打破類型安全泛型是應該提供的。想象一下,您可以將Collection<SomeType>指定給Collection<OtherType>。然後將下面的代碼將讓你把東西,是不是SomeTypeCollection<SomeType>

otherCollection.add(new OtherType()); 

因爲otherCollectionCollection<OtherType>,加入new OtherType()它似乎完全合法的。但otherCollection實際上是指類型SomeType的集合。

,這是允許的:

Collection<SomeType> collection; 
Collection<OtherType> otherCollection = (Collection<OtherType>) (Collection<?>) collection; 

這是type erasure的含義。由於仿製藥在Java編譯器實現幾乎完全的,而不是在運行時,有關通用類型的幾乎所有類型的信息已經通過erased生成字節碼的時間。因此,在運行時,Collection<SomeType>Collection<OtherType>是同一類和兩者都是Collection<?>亞型。通過這種轉換,編譯器只會發出未經檢查的警告,因爲它不知道演員是否安全。

但鑄造,像你在第二個例子中的一個,應避免以避免ClassCastException在運行時。考慮下面的一系列語句:

Collection<SomeType> collection; 
Collection<OtherType> otherCollection = (Collection<OtherType>) (Collection<?>) collection; 
collection.add(new SomeType()); 
otherCollection.add(new OtherType()); 

現在第4語句之後,就沒有辦法對原收集來告訴它包含哪些對象的具體類型;這可能導致ClassCastException在運行時訪問集合中的元素。

+2

未經檢查的警告在此處非常相關。在第一個例子中,編譯器可以肯定地說「這永遠不會工作」。在第二個示例中,您通過遮蔽泛型類型信息來「欺騙」它 - 所以它只能說「我不知道這是否合法,並且可能在運行時失敗」。 –

+1

是@AndrzejDoyle。我認爲不應該像第二個例子那樣投射,因爲它會打破「鍵入集合」的想法。 –

相關問題