[英]Generic Iterator<E> behaves differently when a Raw Type of Collection object is passed to method which accepts Generic parameter
public class Stage2Clone {
public static void main(String[] args) {
ArrayList stringList = new ArrayList();
stringList.add(new Employee(1,"A"));
stringList.add(new Employee(2,"j"));
stringList.add(new Employee(3,"d"));
stringList.add("Hello");
stringList.add(new String("Abc"));
stringList.add(10);
stringList.add(new Integer(100));
System.out.println(stringList);
m1(stringList);
m2(stringList);
}
public static void m1(ArrayList<Employee> al){
Iterator<Employee> iterator = al.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
public static void m2(ArrayList<String> al){
Iterator<String> iterator = al.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
那不是迭代器問題,而是破壞代碼的 System.out.println。 在運行時,collections 中沒有類型檢查(有關詳細信息,請查找 generics 的類型擦除)
您的代碼失敗,因為實際上在 m1 中您正在調用
System.out.println(Object ob)
所以這一切都會被打印出來,因為你收藏中的每一件事都是Object
但是在 m2 調用System.out.println(String str)
並且這是執行的類型檢查,您不能將String
以外的 object 傳遞給此方法
我想向您展示如何防止將來再次發生此類錯誤
簡短的回答:
ArrayList 是一個通用 class 不應該以非通用方式創建,只需更改
這一行:
ArrayList stringList = new ArrayList();
對此:
ArrayList<String> stringList = new ArrayList<>();
之后 java 編譯器不允許你做這樣的壞事。
長答案:
首先讓我們討論一下為什么做這樣的事情是非常糟糕的方法。 我應該說這違反了SOLID原則。 SOLID中的主要原則是liskov替換原則。 您可以在此處閱讀有關此原理的更多信息,但長話短說,當且僅當父 class 的所有屬性都保存時,您可以將子類型的 Object 替換為父類型的 object。 但在這里,您將 ArrayList 類型的ArrayList
分配給ArrayList<Employee>
和ArrayList<String>
類型的 Object,這顯然違反了 liskov-substition 規則。 為了澄清這種情況,讓我們在不改變其邏輯的情況下更改您的m1
方法。 我只想在您的 class 中定義新變量並將迭代器的下一個值分配給該值,然后將其傳遞給 prinLn,所以我們將有這樣的事情:
public static void m1(ArrayList<Employee> al){
Iterator<Employee> iterator = al.iterator();
while(iterator.hasNext()){
Employee employee = iterator.next();
System.out.println(employee);
}
}
我什么也沒做,只定義了新變量? 你認為在這種情況下會發生什么? 在這里,一切都失敗了,您的 m1 方法將不再起作用。 為什么。 因為我們將 ArrayList 類型的值分配給 ArrayList 列表的值,並且我們的程序的行為不可預測。 所以不要嘗試以其他方式更改您的代碼,而只能以正確的形式使用 Generics,否則您將在接下來的夜晚做噩夢。 不要將非泛型 Arraylist 分配給泛型,盡管編譯器允許您這樣做,稍后我將討論為什么編譯器允許您這樣做。 這正是您的代碼中發生的事情,最重要的是,在編譯時無法檢測到這種錯誤,您可以看到在這種情況下發生了運行時錯誤。 簡而言之,在 java 中,您應該以可以在運行時檢測到大量錯誤的方式進行編碼。 在上面的簡短回答中,我告訴您不要以非通用方式創建通用 class 智能讀者應該在這里問的問題是,如果這是壞事,為什么我們被允許以非通用方式創建通用 class 。 It is the decision that have been made by people who were developing java when they introduced Generic in J2SE 5.0 at those time non-generic java classes were used by many developer, for example there was a List class which was not Generic. 為了向后兼容,他們決定以支持舊代碼的方式開發 Generics。 所以通過這種方式,您仍然可以以非通用方式創建通用 class,但這樣您就破壞了 class 的通用行為。 簡而言之,您不應該進行此實例化。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.