我正在运行这一小段代码:
List<String> abc = new ArrayList<String>();
abc.add("something");
List raw = abc;
List<Integer> def = raw;
System.out.println(def.get(0));
我不明白为什么在将包含String
成员的列表分配给Integer
列表时不会抛出异常。此外,Integer
列表如何存储和打印String
?有人可以帮助我吗?
答案 0 :(得分:4)
这就是你不应该使用原始类型的原因。
当你这样做时
List raw = abc;
你自己用列表擦除类型。所以它们没有类型,也没有编译器的错误。要获得泛型的好处,您应该避免使用原始类型。
还要考虑阅读Type Erasing。在运行时,列表不知道它们的类型。类型会被删除,它们只会获得列表中的任何内容。
您预期的错误是编译器错误,同时您避免首先提供类型。因此没有错误。
如果您确实想要查看异常,请尝试将当前列表中的元素分配给整数。虽然编译器不会给你任何错误,但在运行时类型会匹配并且你会遇到异常。
如果查看Raw Types docs,您会看到几乎相同的示例
Box<String> stringBox = new Box<>();
Box rawBox = stringBox;
rawBox.set(8); // warning: unchecked invocation to set(T)
警告显示原始类型绕过泛型类型检查,将不安全代码的捕获推迟到运行时。因此,您应该避免使用原始类型。
答案 1 :(得分:4)
当您编写System.out.println(def.get(0));
时,您将从ArrayList中获取第一个元素并将其传递给System.out.println
。
我猜您会期待一个异常,因为def.get(0)
假设返回Integer
,尽管它在运行时实际返回String
。 但是 System.out.println
接受Object
,它同时接受String
和Integer
,对于参数类型为哪种方法无关紧要。这意味着在运行时,在尝试将返回值传递给方法之前,不会对返回的值进行转换。
如果您尝试将get
返回的值实际存储到Integer
类型的变量中,或者调用类型为Integer
的参数的方法,则只会导致异常导致演员阵容发生:
System.out.println(def.get(0)); // works
Integer integer = def.get(0); // java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
doSomething(def.get(0)); // java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
private static void doSomething(Integer i) {}