public static void main(String[] args) {
List<Integer> integers = new ArrayList<>();
integers.add(5); //element #0
List list = integers;
list.add("foo"); //element #1
integers.get(1); //no error
System.out.println(integers.get(1)); //no error, prints "foo"
Integer i = integers.get(1); //throws ClassCastException
}
我试图理解投射类型变量的过程,声明为泛型类型参数,我有点困惑。
因此,您可以在我提供的示例中看到,在我们创建非参数化List
之后,它引用List<Integer>
的同一个对象,然后我们可以添加任何对象列表(好的,这里没什么可惊讶的),令我困惑的是,我们可以从Integer
中提取非List<Integer> integers
值。为什么在ClassCastException
的第一次或第二次调用中没有integers.get(1)
被抛出?
我假设返回参数类型的方法实际上总是返回Object
,并且隐式尝试将这些返回值转换为
运行时的l值类型或方法参数类型(因为运行时没有泛型),但是以下测试使我确信Integer
始终优先于Object
:
public static void main(String[] args) {
List<Integer> integers = new ArrayList<>();
integers.add(5); //element #0
List list = integers;
list.add("foo"); //element #1
print(integers.get(1));
}
private static void print(Object var) {
System.out.println(var);
}
//this method is entered
private static void print(Integer var) {
System.out.println(var);
}
private static void print(String var) {
System.out.println(var);
}
另一个有趣的事实是,虽然ArrayList
的元素存储在Object[]
数组中,但它们总是在方法get()
中返回之前转换为类型参数中定义的类型:
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
E elementData(int index) {
return (E) elementData[index];
}
所以,如果有人可以指出我一步一步解释这些问题的文件,我会非常感激
答案 0 :(得分:2)
编译器在需要强制转换时插入强制转换。方法System.out.println
的参数类型为Object
,因此不需要转化为Integer
。
对于三个print
方法,选择了类型为Integer
的参数的方法,因此编译器会插入一个强制转换。根据一组复杂的规则,选择使用三种方法中的哪一种在编译时间。这些规则使用通用信息来查看integers.get(1)
类型为Integer
,因此选择Integer
版本并需要强制转换。因此,代码或多或少等同于Java 4
代码
List integers = new ArrayList();
integers.add("foo");
integers.add(Integer.valueOf(5)); // No autoboxing in Java 4!
print((Integer) integers.get(1)); // Cast inserted by compiler
在问题的最后部分中转换为(E)
实际上并没有在运行时执行任何操作,因此不会抛出ClassCastException
。只需要编译代码即可。您告诉编译器,是的,您确定Object
实际上是E
并且稍后不会导致异常(尽管您通过混合原始类型和泛型类型来颠覆它)。 / p>