2014-09-22 121 views
0

我有这样的代码为什么这个泛型代码没有运行时错误?

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()); 

我与泛型代码尝试,我很惊讶地看到一些结果。我有这个具体的问题。

我有一个integer列表。我将它分配给一个没有任何泛型类型的列表l。然后我将一个字符串添加到该列表中。不应该抛出一个运行时异常?列表仍然是一个整数列表吗?

然后我把l投到串列表中?不应该这也抛出一个运行时异常?我不是有效地将integer的数组列表转换为字符串的字符串列表吗?

而在这种情况下,点3,我将一个字符串添加到arr1,即使它应该是字符串arraylist?

我觉得所有三个被质疑的都是相关的吗?任何人都可以向我解释我做错了什么?

回答

4

在编译时强制执行泛型,以便编译器可以进行类型检查。但是,通过type erasure,有关该类型的信息实际上并未在运行时使用。相反,收藏都只包含Object。我相信这最初是为了保持字节码与先前没有泛型支持的java版本的兼容性。

但是,您应该获得有关使用原始类型的警告。

+0

因此预计不会发生运行时异常? – Dude 2014-09-22 16:31:37

+0

正确 - 在同一个集合中存储异构类型是合法的(但通常不鼓励)。为了有用地处理列表,你需要使用'instanceof'或者编码特定元素的类型。 – FatalError 2014-09-22 16:32:09

1

泛型在运行时被擦除,因此可以通过强制转换获得任何类型的List。这是可能的,因为编译后的代码将它看作只是一个List,没有泛型。如果您将列表传递给任何方法,这可能会导致很多问题,并且会收到运行时错误。一般来说,你应该得到一个'未检查'的警告,像这样的事情。

+0

我相信只有在编译时才会出错。 – 2014-09-22 16:29:04

0

要点1:原始列表可以包含任何对象,如果您希望对列表内容强制进行类型检查(在编译时),则需要指定其内容类型。当您将arr指定为l时,您将失去强制类型检查的能力,因此不会抛出Exception并且它是预期的。

第2点:将List转换为ArrayList“可能”(因此没有编译错误)与ArrayList实现List类似。但是,正如第1点所述,您在编译时失去了强制类型检查的能力(直接分配arrarr1不会生成编译错误),这就是为什么您没有ClassCastException。需要注意的是,你甚至可以指定一个new LinkedList()l然后分配larr1,它会编译(但它会引发在运行时类转换例外,因为在这种情况下,投被检测为在运行时是不可能的)

第3点:它是一个字符串ArrayList,你添加一个字符串,它是类型安全的。

+0

我知道没有编译时异常正在通过。我期待第2点的classcast异常。你能解释一下它不会抛出类别表演吗? – Dude 2014-09-22 16:49:09

+0

''l''的类型是''List''(而不是''ArrayList '''''''List''的对象可以是一个ArrayList ''?是的,它是*可能*(但不能在编译时验证,因此在编译期间没有错误消息)。然而,在编译时,验证将''String''实例插入到''arr1''中(这就是为什么你可以添加''“12”'',但不能添加''12'')在运行时,你正在将'ArrayList'投射到''ArrayList''(在运行时没有泛型),因此没有类转换异常。 – Kraal 2014-09-22 16:55:32

相关问题