运行时的泛型

时间:2017-01-03 08:12:57

标签: java generics

有两个节目  为什么第一个代码代码有效?我希望它在访问元素时抛出一个运行时异常,因为添加了String而不是Integer

类似地..  第二个代码是在访问元素时抛出运行时异常,尽管它能够轻松地在arrayList中添加Integer,尽管它声明它可以保存String。

在这两个代码中,我们成功添加了不同的数据类型,但访问元素时似乎出现了问题

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {

        ArrayList<Integer> arrayList = new ArrayList<>();
        Test.addToList(arrayList);

        System.out.println(arrayList.get(0));
    }

    public static void addToList(ArrayList arrayList) {
        arrayList.add("i");

    }
}






import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {

        ArrayList<String> arrayList = new ArrayList<>();
        Test.addToList(arrayList);

        System.out.println(arrayList.get(0));
    }

    public static void addToList(ArrayList arrayList) {
        arrayList.add(1);

    }
}

2 个答案:

答案 0 :(得分:3)

由于type erasure,您可以在两种情况下添加元素。在运行时,该类并不知道它被声明为$details = Details::with(['header'=>function($query) use ($id){ $query->where('customer_id', $id); }])->get() ,只是它被声明为new ArrayList<String>()

new ArrayList()的情况下,方法的编译时重载决策起作用。 printlnPrintStreamSystem.out有几个重载。其中包括:

println

Java编译器将选择最具体的那些。在... void println(Object x); void println(String x); 情况下,它是第一个,在ArrayList<Integer>情况下,它是第二个。一旦它这样做,作为类型擦除处理的一部分,它会将原始ArrayList<String>调用的Object结果转换为所需类型,但前提是必须进行转换。

ArrayList::get(int)调用的情况下,不需要强制转换(ArrayList<Integer>返回一个Object,这正是方法所期望的),因此javac省略了它。在ArrayList::get(int)调用的情况下,是必要的,因此javac会添加它。你看到的是什么:

ArrayList<String>

实际编译为:

System.out.println(arrayList.get(0));

但元素不是String,而这是导致ClassCastException的原因。

答案 1 :(得分:1)

泛型仅在编译期间存在。它们在编译后从二进制代码中删除,这称为“类型擦除”。这主要是出于向后兼容的原因。

如果编译时没有警告且没有手动编译,则无法滥用泛型,因为这会导致编译器错误和一些警告。

当您声明您希望功能ArrayList时,没有任何泛型指示。您禁用所有编译时检查。你应该对此发出警告。在这种情况下使用泛型参数的任何地方都只接受Object

但是当你使用get()访问对象时,会发生一些隐藏的事情,一个演员。

ArrayList<String> list = new ArrayList<>();
list.add("Hello");
String s = list.get(0);

最后一行被重写为:

String s = (String) list.get(0);

如果列表没有返回String类型的内容,则会失败。 当您仅在列表中使用泛型时,它将只有String(或您的代码将无法编译)。但是,由于您已将非String对象放入列表中,因此对强制转换的类型检查将失败。