簡體   English   中英

泛型迭代器<e>當集合的原始類型 object 傳遞給接受通用參數的方法時,行為不同</e>

[英]Generic Iterator<E> behaves differently when a Raw Type of Collection object is passed to method which accepts Generic parameter

  • 當調用 m1() 時,output 會打印 arraylist 的所有元素。
  • 當調用 m2() 時,獲取 ClassCastException 說:線程“主”中的異常 java.lang.ClassCastException:test.Employee 無法轉換為 java.lang.String。
  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.

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