原始类型在 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++。)
我正在学习泛型,但我有一个误解。
例如我有这个简单的代码:
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++。)