原始类型在 Java 中如何工作?

How raw type works in Java?

我正在学习泛型,但我有一个误解。

例如我有这个简单的代码:

import java.util.ArrayList;

public class DemoApp {

    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add(1);
        System.out.println(list.get(0).getClass().getName()); 
        int value = (Integer) list.get(0);
    }
}

我不明白为什么我要把 list.get(0) 转换成 Integer 因为这个语句 System.out.println(list.get(0).getClass().getName()); 有这个结果 java.lang.Integer

如果我使用此语句 int value = list.get(0); 我会收到此错误:Type mismatch: cannot convert from Object to int... 我真的不明白,list.get(0)Object 还是Integer

ArrayList 原始类型。它就像一个 ArrayList<Object>。您可以向其中添加对象的所有子类型(这几乎是全部)。

因此,如果您从列表中取回一个对象,那么它是一个 Object - 在编译时您无法知道它是 Integer 还是 String

使用 ArrayList<Integer> 时不需要强制转换。

编辑:

import java.util.ArrayList;

public class DemoApp {

    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add(1); // an int
        list.add("Test"); // an String
        list.add(new Object()); // and empty

        var rnd = RandomUtils.random(list.size());

        for (Object value : list)      
           System.out.println(value.getClass().getName()); 


       list.get(rnd) // so, what is the type of the object?
       // the compiler cannot know it (compile-time), you need to run the program and check it (runtime)

    }
}

编辑2: 另见 https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html

因为当您使用原始类型时(比如 ArrayList 没有任何通用类型)Java 假定该列表中的元素类型是 Object。所以 list.get(0) 将 return 类型的引用 Object。因此你需要投射。

return 由 list.get(0) 编辑的对象是 Integer 类型,但对它的引用是 Object 类型,这就是编译器投诉的原因,因为你想分配引用类型 Object 到原始类型的变量 int.

Plain ArrayList 表示 ArrayList<?>,表示包含未指定类型对象的 ArrayList。由于所有对象都派生自 Object,因此关于这些对象,您最多只能说它们是对象。

事实上,在 运行 时间,一个特定的对象可能变成一个整数(也)并不能解决编译时对象类型未知的问题。

考虑:

list.add(1);
list.add("two");
for (int i=0; i<list.size(); i++)
    System.out.println(list.get(i).getClass().getName()); 

现在 list.get(i) 的类型是什么?

我的问题是:为什么要使用原始类型?

list.get(0).getClass().getName() 将访问 List 中的一个元素,并在运行时发现它确实是一个整数。不过也可以是其他任何东西。

编译器在编译时知道的是您的list包含类型Object的项目,参见List.get(int)的签名。所以它不能证明 int value = list.get(0) 永远是正确的。您必须显式投射。

Java 中的整个泛型只是编译时的。这是一种告诉编译器如何将类型参数化的 classes 限制为特定类型的方法,从而保证 在编译时 对它们的操作确实是正确的。也就是说,编译器不允许您将 String 放入 List<Integer>.

在运行时,类型参数化信息被擦除。 JVM 依靠编译器完成生成正确代码的工作来运行。在运行时没有任何东西允许 JVM 知道 List 的内容是什么类型; ArrayList 对任何 class 参数都有一个实现。 (这不同于 C# 或 C++。)