簡體   English   中英

為什么第4行不生成未經檢查的異常?

[英]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號線不是指原始類型的任何變量-它是指調用getList<String> ,並指派返回值的String變量。 如果您認為這應該產生警告,請顯示Java語言規范的哪一部分建議警告是適當的 - 我認為您會發現很難這樣做。

第4行不產生編譯時警告,因為ls的類型是List<String> ,這意味着它的get方法返回Stringnull 任何違規都將在編譯時捕獲並導致ClassCastException

編輯:

編譯器知道有許多事情,字節碼驗證器和解釋器沒有。

  1. 通用類型
  2. 僅編譯時注釋
  3. 檢查異常
  4. 外層私人

java編譯器知道這些事情並因此指出它們的使用中的錯誤,但是字節碼驗證器和解釋器不這樣做,因此它在生成用於解釋器的.class文件部分時“擦除”它們。

所以編譯的步驟是

  1. 通過查找.java.class文件來查找所需的所有類。
  2. 確保所有類型檢查。
  3. 擦除解釋器不需要的信息(但是如果在其輸入CLASSPATH上使用.class調用javac,則將其隱藏起來)。
  4. 生成輸出.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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM