ArrayList <Integer>自动将其类型更改为ArrayList <String>

kah*_*fan 7 java types arraylist erasure

public void run(){
    setFont("Courier-24");
    //Define list as ArrayList<Integer>
    ArrayList<Integer> list = new ArrayList<Integer>();
    readList(list);
}

private void readList(ArrayList list){
    list.add("Hello");
    list.add(2);
    println("list = "+list);
    println("Type of list = "+list.get(0).getClass());
    println("Type of list = "+list.get(1).getClass());
}
Run Code Online (Sandbox Code Playgroud)

结果:

list = [Hello,2]
list的类型= class java.lang.String
list的类型= class java.lang.Integer

这是我的代码和结果.我的问题是,Integer类型的ArrayList如何可以存储String对象?现在列表的类型是什么?这是什么机制?

T.J*_*der 6

Java的泛型实际上并没有改变底层的类或对象,它们只提供(大多数)围绕它们的编译时语义.

通过传入一个ArrayList<Integer>期望ArrayList(可以容纳任何东西)的方法,你绕过了编译器为你提供类型安全的能力.

Java泛型教程解释了这一点,为什么Java的泛型实现这种方式.特别是这个页面关注它:

泛型被引入到Java语言中,以便在编译时提供更严格的类型检查并支持泛型编程.为了实现泛型,Java编译器将类型擦除应用于:

  • 如果类型参数是无界的,则用泛型或对象替换泛型类型中的所有类型参数.因此,生成的字节码仅包含普通的类,接口和方法.
  • 如有必要,插入类型铸件以保持类型安全.
  • 生成桥接方法以保留扩展泛型类型中的多态性.

类型擦除确保不为参数化类型创建新类; 因此,泛型不会产生运行时开销.

没有说的是,这也允许使用泛型(如你的run)编写的代码与没有泛型(如你的readList)编写的代码进行交互,这对于使用庞大的库向一个非常完善的语言添加一个特性很重要base(就像在将泛型添加到Java时一样).