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

时间:2014-09-22 16:20:01

标签: java generics

我有这段代码

    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?

我觉得这三个问题中的所有人都有关系吗?谁能向我解释我做错了什么?

3 个答案:

答案 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,你添加一个字符串,它是类型安全的。

相关问题