2012-02-23 26 views
0

我有下面的代碼段試圖瞭解泛型

public static void main(String[] args) { 
     ArrayList<Integer> iList = new ArrayList(); 
     iList = returList(); 
     for (int i = 0; i < iList.size(); i++) { 
      System.out.println(iList.get(i)); 
     } 
    } 

    public static ArrayList returList() { 
     ArrayList al = new ArrayList(); 
     al.add("S"); 
     al.add(1); 
     return al; 
    } 

現在我的查詢是爲什麼該ArrayList正在接受管線原始ArrayList對象創建「的ArrayList ILIST =新的ArrayList();」甚至從方法調用返回均勻的情況。

現在,哪種類型的數據將會在那裏,泛型將暗示什麼?我看不到編譯錯誤,而且這些代碼甚至運行良好。

+1

參見:http://stackoverflow.com/questions/490091/java-generics – Matthias 2012-02-23 11:56:16

+0

@adarshr意味着當你找到它 – 2012-02-23 12:24:51

回答

1

由於Java泛型的實現方式(請參見Type Erasure的介紹性說明),可以創建泛型類的「原始」類型實例,然後將它們轉換爲泛型版本,如iList的賦值。這會導致編譯器警告,因爲它可能是不安全的操作。你可以將任何你喜歡的類型添加到一個原始的ArrayList中(它相當於ArrayList),但是如果你將它轉換爲一個更具體的泛型類型,你可能會收集到一個不一致的集合。

在你的例子中,你已經在returList中創建了這樣一個列表。然而,你的代碼不會顯示這個,因爲println()不依賴於傳遞給它的列表元素的類型。行如

Integer val = iList.get(i); 

添加到您的for循環和運行代碼,你會得到一個ClassCastException爲你的程序試圖將字符串"s"強制轉換爲Integer

當泛型集合不一致時,只有在嘗試訪問使用泛型類型的不一致元素時纔會發現。

0

因爲這是錯誤的。這是它做正確的方式:

public static void main(String[] args) { 
    List<Integer> iList = returList(); 
    for (int i = 0; i < iList.size(); i++) { 
     System.out.println(iList.get(i)); 
    } 
} 

public static List<Integer> returList() { 
    List<Integer> al = new ArrayList<Integer>(); 
    //al.add("S"); This line can't compile now! 
    al.add(1); 
    return al; 
} 

注意要點:

  1. 編程對接口
  2. 避免不必要的初始化
  3. 使用類型參數的實施,以及(賦值運算符的RHS )
+0

會有什麼這行代碼並處現在 「ArrayList的 ILIST =新需要標註了正確的答案數組列表();' – Shiv 2012-02-23 12:00:10

+0

一個生硬的數組列表? – Shiv 2012-02-23 12:00:38

+0

這行代碼只會給你一個警告,如@ Perception的答案中所示。 – adarshr 2012-02-23 12:02:01

1

泛型被創建爲對開發者的幫助,但是您有使用它們以獲益。您的IDE會警告您ArrayList的原始用法:

ArrayList is a raw type. References to generic type ArrayList<E> should be parameterized 

但是它並不能阻止你掛你自己,不會。請注意,在某些IDE中,實際上可以強制這些是編譯錯誤,這可能是您正在尋找的。

現在就您的列表中的內容而言,它就是您放入它的內容。請記住,泛型只不過是「語法糖」,編譯器提示從生成的類中刪除完全。所以在運行時,沒有關於對象具有什麼通用類型的指示。在你的情況下,你的代碼工作正常,因爲你正在做的是打印出列表內容。所有對象都會自動轉換爲字符串!試試這個,而不是用於娛樂和遊戲:

public static void main(String[] args) { 
     ArrayList<Integer> iList = new ArrayList(); 
     iList = returList(); 
     for (final Integer i: iList) { 
      System.out.println(i.intValue()); 
     } 
} 
+0

這是有道理的。但不是我正在尋找的東西。 – Shiv 2012-02-23 12:00:53

+0

@Shivaji - 不知道什麼是沒有意義的。但我在第二個問題中增加了更多細節。 – Perception 2012-02-23 12:06:17

+0

耶我在這裏看到一些奇怪的事情..我只是改變了我這樣的代碼 公共靜態無效的主要(字串[] args){ \t \t的ArrayList ILIST; // =新的ArrayList(); \t \t iList = returList();對於(int i = 0; i 」); \t \t \t System.out.println(iList.get(i).getClass()); \t \t} } 現在即時看到奇怪的結果..類種姓例外。真的無法弄清楚這件事。你能給我解釋一下嗎? – Shiv 2012-02-23 13:26:47

0

這是回答here

爲什麼原始類型的許可?

原始類型 被允許在語言中主要用於促進 與非通用(遺留)代碼的接口。

例如,如果您有一個將列表作爲 參數的非泛型傳統方法,則可以將參數化類型(例如List)傳遞給 該方法。相反,如果您有返回列表的方法 ,則可以將結果分配給List 類型的參考變量,前提是您知道某種原因返回的列表確實是 字符串列表。

+0

因此,釋放genrics上下文的機會開始付諸行動不是嗎? – Shiv 2012-02-23 12:03:34

+0

如果你想強制執行它(這是一件好事),那麼它就是強制執行的,但是舊代碼不應該中斷,因爲你想向語言中添加新的特性,這就是爲什麼它可以接受原始類型。 – 2012-02-23 12:14:10

0

有點泛型的歷史可能有助於解釋一些古怪。

當最初爲Java提出泛型時,假設必須在不更改基礎.class格式的情況下引入更改。所以泛型被實現爲原始類型的一個薄層。稱爲類型擦除的技術成爲解決方案。這意味着編譯器會刪除所有的泛型信息,以便在運行時不提供通用信息。

如果你不能依賴源代碼中顯示的類型,這會產生令人討厭的後果。

這就是你的例子中發生的事情。

查看http://docs.oracle.com/javase/tutorial/java/generics/erasure.html瞭解更多詳情。

請注意,對於Java 5,.class格式最終更改爲適應自動裝箱。由於時間限制,班級格式正在發生變化,因此可以正確完成仿製藥的事實並未被利用。