考虑以下代码:
class AA { }
class BB extends AA { }
public class Testing {
public static void main(String[] args) {
BB[] arr = new BB[10];
AA[] arr2 = arr;
BB b = new BB();
AA a = new AA();
arr2[0] = a; // ArrayStoreException at runtime
arr2[1] = b;
List<BB> listBB = new ArrayList<>();
List listAA = listBB;
listAA.add("hello world.txt");
}
}
在上面的示例中,当我尝试 arr2[0] = a
时,我得到了 ArrayStoreException
。这意味着数组会记住它必须接受的类型。但是 List
不记得它们。它只是编译并运行良好。当我检索对象 BB
时,将抛出 ClassCastException
。
所以问题是:
数组如何记住它的类型(我知道它被称为“具体化”)。这究竟是怎么发生的?
以及为什么只有数组被赋予了这种权力,而
ArrayList
却没有,尽管它在其底层使用了一个数组。为什么在编译时无法检测到
ArrayStoreException
,即当我执行arr2[0] = a
时,可能会导致编译器错误,而不是在运行时检测它。
谢谢。
最佳答案
与泛型不同,数组的类型信息是在运行时存储的。从一开始,这就是 Java 的一部分。在运行时,
AA[]
可以区别于BB[]
,因为 JVM 知道它们的类型。安
ArrayList
(以及 Collections 框架的其余部分)使用泛型,它受类型删除的影响。在运行时,泛型类型参数不可用,因此ArrayList<BB>
与ArrayList<AA>
无法区分;他们都只是ArrayList
s 到 JVM。编译器只知道
arr2
是AA[]
.如果您有AA[]
,编译器只能假设它可以存储AA
.编译器不会检测到您放置AA
的类型安全问题。在真正的BB[]
在那里,因为它只看到AA[]
引用。与泛型不同,Java 数组是协变的,因为BB[]
是AA[]
因为一个BB
是AA
.但这引入了您刚才演示的可能性 -ArrayStoreException
, 因为arr2
所指的对象真的是BB[]
,它不会处理AA
作为一个元素。
关于java - Java中的数组 "remember"它们的类型如何?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21711772/