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

ArrayList<Integer> automatically change its type to ArrayList <String>

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());
}

结果:

list = [Hello, 2]
Type of list = class java.lang.String
Type of list = class java.lang.Integer

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

在您的 readList 方法的参数中,您没有将它限制为仅 Integer 值类型,因此 list 无法获得编译时检查的好处,必须诉诸到运行时类型检查。

Java 的泛型实际上并没有改变底层的 class 或对象,它们只是提供(大部分)围绕它们的编译时语义。

通过将 ArrayList<Integer> 传递给需要 ArrayList 的方法(可以容纳 任何东西 ),您将绕过编译器为您提供的能力具有那种类型的安全性。

Java Generics Tutorial explains this, and why Java implements generics this way. This page,特别关注:

Generics were introduced to the Java language to provide tighter type checks at compile time and to support generic programming. To implement generics, the Java compiler applies type erasure to:

  • Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
  • Insert type casts if necessary to preserve type safety.
  • Generate bridge methods to preserve polymorphism in extended generic types.

Type erasure ensures that no new classes are created for parameterized types; consequently, generics incur no runtime overhead.

没有说明的是,这还允许 使用 泛型编写的代码(如您的 run)与使用 编写的代码进行交互 泛型(就像你的 readList),这在向具有庞大库基础的非常成熟的语言添加功能时很重要(就像在向 Java 添加泛型时一样) .

声明

ArrayList list

方法中的readList等同于

ArrayList<Object> list

很明显String是Object,Integer也是。当传递给 println 时,两者都将使用自己的方法进行 toString。

当您声明时:

 private void readList(ArrayList list)

您没有为此 ArrayList 指定任何类型,因此默认情况下它是 Object.

类型

StringInteger(实际上java中的所有类)都是Object的子类型。因此可以将它们添加到列表中。

有关没有类型的泛型的更多信息,请阅读 here。简而言之,泛型类型仅用于编译时检查,因此您不会添加错误的类型(稍后可能会导致异常。在这种情况下,您对 StringInteger 的操作是兼容的,幸运的是没有错误)。

我认为没有作为参数传递的泛型规范的 ArrayList 类型被假定为 ArrayList。 String 和 Integer 都继承了 Object,因此它们都可以添加到列表中。但是 ArrayList 元素是对象类型。