我有这段代码
ArrayList<Integer>arr = new ArrayList<>();
arr.add(1);
arr.add(2);
List l = arr;
l.add("12");// should't this throw an runtime exception? Point1
l.add("123");
System.out.println(l.size());
ArrayList<String>arr1 =(ArrayList<String>) l;// should't this throw an runtime execptions? Point2
arr1.add("12"); //Point 3
System.out.println(arr1.size());
我正在尝试使用泛型代码,我很惊讶地看到了一些结果。我有这个具体的问题。
我有一个整数的arraylist。我将它分配给列表l,它没有任何泛型类型。然后我在该列表中添加一个字符串。不应该抛出运行时异常吗? l list仍然是整数的arraylist?
然后我将l转换为字符串的arraylist?难道这不会引发运行时异常吗?我有效地将整数的arraylist转换为字符串的ararylist吗?
在这种情况下,第3点,我正在为arr1添加一个字符串,即使它应该是字符串的arraylist?
我觉得这三个问题中的所有人都有关系吗?谁能向我解释我做错了什么?
答案 0 :(得分:4)
在编译时强制执行泛型,以便编译器可以进行类型检查。但是,通过 type erasure ,有关该类型的信息实际上并未在运行时使用。相反,集合都只包含Object
。我相信这最初是为了保持字节码兼容以前没有普通支持的java版本。
但是,您应该收到有关使用原始类型的警告。
答案 1 :(得分:1)
泛型在运行时被删除,因此可以通过强制转换来获得List
中的任何类型。这是可能的,因为编译后的代码只将其视为List
,没有泛型。如果将列表传递给任何方法,并且将发生运行时错误,这可能会导致许多问题。一般来说,你应该得到一个未经检查的&#39;警告这样的事情。
答案 2 :(得分:0)
第1点:原始列表可以包含任何对象,如果要对列表内容强制执行类型检查(在编译时),则需要指定其内容类型。当您将arr
分配给l
时,您将无法执行类型检查,因此不会抛出异常,这就是预期的结果。
第2点:将一个List转换为ArrayList“可能”(这就是为什么没有编译错误),因为ArrayList实现了List。但是,如第1点所述,您无法在编译时强制执行类型检查(直接将arr
分配给arr1
不会生成编译错误)这就是您没有ClassCastException的原因。请注意,您甚至可以将new LinkedList()
分配给l
,然后将l
分配给arr1
并且它已编译(但它会在运行时引发类强制转换异常,如同在这种情况下,演员在运行时被检测为不可能)
第3点:它是一个字符串的ArrayList,你添加一个字符串,它是类型安全的。