Java 向字符串的通用ArrayList添加整数时出现编译时错误
我知道这个问题以前被问过多次,但我正在寻找一个基于类型擦除的答案Java 向字符串的通用ArrayList添加整数时出现编译时错误,java,generics,arraylist,collections,Java,Generics,Arraylist,Collections,我知道这个问题以前被问过多次,但我正在寻找一个基于类型擦除的答案 为什么编译器在将Integer添加到ArrayList时出错?我想通过在ArrayList中键入擦除和add方法的字节码来理解这一点 这与类型擦除或字节码无关。编译器在删除泛型类型参数并生成字节码之前会给出此错误 将整数添加到数组列表时,编译器只会给出一个错误,因为整数不是字符串的子类 泛型只是在编译时添加了一层类型安全性。如果使用原始ArrayList而不是ArrayList,则可以将Strings和Integers添加到Arr
为什么编译器在将
Integer
添加到ArrayList
时出错?我想通过在ArrayList
中键入擦除和add
方法的字节码来理解这一点 这与类型擦除或字节码无关。编译器在删除泛型类型参数并生成字节码之前会给出此错误
将整数
添加到数组列表
时,编译器只会给出一个错误,因为整数
不是字符串
的子类
泛型只是在编译时添加了一层类型安全性。如果使用原始
ArrayList
而不是ArrayList
,则可以将String
s和Integer
s添加到ArrayList
。但是,无论您使用的是ArrayList
还是ArrayList,生成的字节码都是相同的,即使类型擦除意味着在执行时VM无法区分ArrayList
和ArrayList
(它们都只是ArrayList
的实例)编译器确实知道类型参数,并且知道什么是安全的
因此,如果你有:
ArrayList<Integer> integers = new ArrayList<Integer>();
integers.add("foo");
现在没有从String
到Integer
的转换,因此这些重载都不适用于调用integers.add(“foo”)
,因此出现编译时错误
基本上,泛型提供两种功能:
- 编译时的安全性,以避免这种损坏的代码;如果您已经说过列表应该只包含
整数
引用,编译器将不允许您向其添加字符串
引用
- 类型转换方面的简单性—当带有类型参数
T
的类的方法返回类型为T
的值,并且编译器知道T
是什么时,它可以从已擦除的类型(通常是对象
)向类型参数插入适当的类型转换。这就是为什么:
List<Integer> integers = getListFromSomewhere();
Integer x = integers.get(0);
List integers=getListFromSomewhere();
整数x=整数。获取(0);
works-编译器在调用代码中添加强制转换。(执行时仍会检查该强制转换。)
让我们从一个小例子开始(请注意,这使用了;它们是邪恶的)
因为字符串
不是整数
。我们可以使用javap-v
35: invokeinterface #37, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
40: checkcast #43 // class java/lang/Integer
43: astore_3
44: getstatic #45 // Field java/lang/System.out:Ljava/io/PrintStream;
注意,在编号为40的行上,演员阵容失败。泛型类型用于编译时类型检查,在运行时(几乎)一切都是一个对象
我读到的是擦除指用泛型类型替换对象,所以它们都是Object的子类,但是你用字符串声明你的ArrayList,现在编译器知道了,如果编译器不会给你一个错误,然后它将在运行时崩溃,并带有ClasscastExcpetion@user2653926但只有当代码通过编译时,才会发生擦除。如果无法通过编译,则不会生成字节码,也不会进行擦除。
public static void main(String[] args) {
List<String> strings = Arrays.asList("Hello");
List<Integer> al = new ArrayList(strings);
for (Integer v : al) {
System.out.println(v);
}
}
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at com.stackoverflow.Example.main(Example.java:11)
35: invokeinterface #37, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
40: checkcast #43 // class java/lang/Integer
43: astore_3
44: getstatic #45 // Field java/lang/System.out:Ljava/io/PrintStream;