[英]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.