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;