[英]Why doesn't line 4 generate an unchecked exception?
/*1.*/ List l = new ArrayList<Number>();
/*2.*/ List<String> ls = l; // unchecked warning
/*3.*/ l.add(0, new Integer(42)); // another unchecked warning
/*4.*/ String s = ls.get(0);
如果第2行和第3行產生未經檢查的警告,那么為什么第4行不會生成未經檢查的警告,因為編譯器不知道'ls'指的是什么( List<String>
或List<Integer>
)。
(注意:從OP的原始帖子進行編輯,以使代碼顯示為可能的 - 特別是包含List<E>
的類型參數。)
編譯器認為 ls
將真正引用字符串列表 - 如果尚未進行危險操作,則第4行將是“安全的”(就類型安全而言) - 即第2行。
如果不涉及其他警告, List<String>
應始終引用僅包含對字符串(或null)的引用的列表。 但是如果你已經打破了類型安全性,那么所有的賭注都是關閉的(除了VM將在執行時捕獲那些類型的違規)。
警告顯示哪條線是危險的 - 在這種情況下,你正在使用原始類型的地方,即你說,“好吧,我們這里有一個清單。我不知道它里面有什么。”
4號線不是指原始類型的任何變量-它僅是指調用get
上List<String>
,並指派返回值的String
變量。 如果您認為這應該產生警告,請顯示Java語言規范的哪一部分建議警告是適當的 - 我認為您會發現很難這樣做。
第4行不產生編譯時警告,因為ls
的類型是List<String>
,這意味着它的get
方法返回String
或null
。 任何違規都將在編譯時捕獲並導致ClassCastException
。
編輯:
編譯器知道有許多事情,字節碼驗證器和解釋器沒有。
java編譯器知道這些事情並因此指出它們的使用中的錯誤,但是字節碼驗證器和解釋器不這樣做,因此它在生成用於解釋器的.class
文件部分時“擦除”它們。
所以編譯的步驟是
.java
和.class
文件來查找所需的所有類。 .class
調用javac,則將其隱藏起來)。 .class
文件。 第4行沒有給出警告,因為ls
被聲明為List<String>
, ls.get(0)
返回一個String(就編譯器所知),並且你將它分配給一個String變量s
對於編譯器來說,一切看起來都是正確的 - 它沒有看到你“非法”將它指向List<Integer>
的事實。
但是,您將獲得ClassCastException 運行時 。
第4行絕對沒問題。 您可能認為您的代碼是:
String s = l.get(0); // this will not compile without the cast
第4行不保證未經檢查的警告,因為它不會引入類型錯誤的可能性。 ls
的聲明表示它是List<String>
,而List<String>
包含String
。 它不是一種稱為堆污染的病態情況,只有在未經檢查的警告被錯誤地抑制時才會出現,但這不是第4行的錯誤。
但是,第4 ClassCastException
運行時拋出ClassCastException
,因為編譯器知道堆污染的可能性,並在調用其上的方法之前發出額外的強制轉換來驗證返回的對象是否是正確的類型。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.