2013-08-28 5 views
3

下面的代碼JLS 6/7的哪些更改會導致以下未檢查的代碼,其集合和泛型在Java 7中可用?

import java.util.*; 
import java.io.*; 

@SuppressWarnings("unchecked") 
List<Serializable> list = (List<Serializable>) (List<?>) 
    Collections.singletonList(new Object()); 

for (Object el : list) { // -> ClassCastException 
    System.out.println(el); 
} 

是正確的Java(即使代碼是可疑的)。使用javacjava 6使用它和

它是一個語言的變化時,修正了或隱藏的功能拋出

Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.io.Serializable 

,同時它在運行時錯誤?

(注:代碼與Eclipse編譯運行,而無需對所有的Eclipse版本檢查錯誤 - 太陽神開普勒)

+0

在Java 6中,'?'是'?擴展Object'不可序列化我假設Java 7對於你可以投入'''的東西更加自由。如果你只是施放'(List)',這將在兩個版本中都起作用。 –

+2

http://stackoverflow.com/questions/15389994/lazy-class-cast-in-java/15391048#15391048 – ZhongYu

+0

爲了清楚起見,您可以評論在Java 6中拋出異常的那一行嗎?我假設它是(for Object el:list){'。 –

回答

2

你通過添加原料Object到集合(您在哪個污染堆做投舞會發生)。這在技術上不合法,但它是一個錯誤。

當您從隱式迭代器中提取值時,Java 6編譯器看起來是立即投射,而Java 7編譯器不是。如果它不需要(因爲控股變量只是Object),不會投射到Serializable更爲有效,但就JLS而言,此行爲未定義。嘗試在兩個.class文件上運行javap,然後查看for循環周圍的代碼(可能正好在invokeinterface調用Iterator.next()後)。

+0

謝謝你的解釋,我知道我的問題聽起來很愚蠢,但我真的很明白接下來會發生什麼,知道該讀什麼和讀字節碼,我甚至知道任何這樣的我的問題是 - **爲什麼**在Sun/Oracle Java 6和7之間的行爲發生了變化? –

+0

這個問題的答案是:在我的回答中是一個旁白評論;顯然,spec沒有指定隱式轉換所需的點,在這種情況下,Java 7編譯器可以通過新的靜態分析邏輯觀察到你總是處理引用無論如何,它都會作爲一個普通的「對象」退出收藏集,因此它不會浪費指示執行不相關的演員。 – chrylis