2014-09-22 156 views
0

我有這樣的代碼爲什麼這個泛型代碼沒有運行時錯誤?

ArrayList<Integer>arr = new ArrayList<>(); 
    arr.add(1); 
    arr.add(2); 

    List l = arr; 
    l.add("12");// should't this throw an runtime exception? Point1 
    l.add("123"); 
    System.out.println(l.size()); 
    ArrayList<String>arr1 =(ArrayList<String>) l;// should't this throw an runtime execptions? Point2 

    arr1.add("12"); //Point 3 
    System.out.println(arr1.size()); 

我與泛型代碼嘗試,我很驚訝地看到一些結果。我有這個具體的問題。

我有一個integer列表。我將它分配給一個沒有任何泛型類型的列表l。然後我將一個字符串添加到該列表中。不應該拋出一個運行時異常?列表仍然是一個整數列表嗎?

然後我把l投到串列表中?不應該這也拋出一個運行時異常?我不是有效地將integer的數組列表轉換爲字符串的字符串列表嗎?

而在這種情況下,點3,我將一個字符串添加到arr1,即使它應該是字符串arraylist?

我覺得所有三個被質疑的都是相關的嗎?任何人都可以向我解釋我做錯了什麼?

回答

4

在編譯時強制執行泛型,以便編譯器可以進行類型檢查。但是,通過type erasure,有關該類型的信息實際上並未在運行時使用。相反,收藏都只包含Object。我相信這最初是爲了保持字節碼與先前沒有泛型支持的java版本的兼容性。

但是,您應該獲得有關使用原始類型的警告。

+0

因此預計不會發生運行時異常? – Dude 2014-09-22 16:31:37

+0

正確 - 在同一個集合中存儲異構類型是合法的(但通常不鼓勵)。爲了有用地處理列表,你需要使用'instanceof'或者編碼特定元素的類型。 – FatalError 2014-09-22 16:32:09

1

泛型在運行時被擦除,因此可以通過強制轉換獲得任何類型的List。這是可能的,因爲編譯後的代碼將它看作只是一個List,沒有泛型。如果您將列表傳遞給任何方法,這可能會導致很多問題,並且會收到運行時錯誤。一般來說,你應該得到一個'未檢查'的警告,像這樣的事情。

+0

我相信只有在編譯時纔會出錯。 – 2014-09-22 16:29:04

0

要點1:原始列表可以包含任何對象,如果您希望對列表內容強制進行類型檢查(在編譯時),則需要指定其內容類型。當您將arr指定爲l時,您將失去強制類型檢查的能力,因此不會拋出Exception並且它是預期的。

第2點:將List轉換爲ArrayList「可能」(因此沒有編譯錯誤)與ArrayList實現List類似。但是,正如第1點所述,您在編譯時失去了強制類型檢查的能力(直接分配arrarr1不會生成編譯錯誤),這就是爲什麼您沒有ClassCastException。需要注意的是,你甚至可以指定一個new LinkedList()l然後分配larr1,它會編譯(但它會引發在運行時類轉換例外,因爲在這種情況下,投被檢測爲在運行時是不可能的)

第3點:它是一個字符串ArrayList,你添加一個字符串,它是類型安全的。

+0

我知道沒有編譯時異常正在通過。我期待第2點的classcast異常。你能解釋一下它不會拋出類別表演嗎? – Dude 2014-09-22 16:49:09

+0

''l''的類型是''List''(而不是''ArrayList '''''''List''的對象可以是一個ArrayList ''?是的,它是*可能*(但不能在編譯時驗證,因此在編譯期間沒有錯誤消息)。然而,在編譯時,驗證將''String''實例插入到''arr1''中(這就是爲什麼你可以添加''「12」'',但不能添加''12'')在運行時,你正在將'ArrayList'投射到''ArrayList''(在運行時沒有泛型),因此沒有類轉換異常。 – Kraal 2014-09-22 16:55:32

相關問題