java - Java中的数组 "remember"它们的类型如何?

标签 java arrays generics arraylist

考虑以下代码:

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

所以问题是:

  1. 数组如何记住它的类型(我知道它被称为“具体化”)。这究竟是怎么发生的?

  2. 以及为什么只有数组被赋予了这种权力,而 ArrayList 却没有,尽管它在其底层使用了一个数组。

  3. 为什么在编译时无法检测到ArrayStoreException,即当我执行arr2[0] = a时,可能会导致编译器错误,而不是在运行时检测它。

谢谢。

最佳答案

  1. 与泛型不同,数组的类型信息是在运行时存储的。从一开始,这就是 Java 的一部分。在运行时,AA[]可以区别于 BB[] ,因为 JVM 知道它们的类型。

  2. ArrayList (以及 Collections 框架的其余部分)使用泛型,它受类型删除的影响。在运行时,泛型类型参数不可用,因此 ArrayList<BB>ArrayList<AA> 无法区分;他们都只是ArrayList s 到 JVM。

  3. 编译器只知道arr2AA[] .如果您有 AA[] ,编译器只能假设它可以存储 AA .编译器不会检测到您放置 AA 的类型安全问题。在真正的BB[]在那里,因为它只看到 AA[]引用。与泛型不同,Java 数组是协变的,因为 BB[]AA[]因为一个 BBAA .但这引入了您刚才演示的可能性 - ArrayStoreException , 因为 arr2 所指的对象真的是BB[] ,它不会处理 AA作为一个元素。

关于java - Java中的数组 "remember"它们的类型如何?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21711772/

相关文章:

java - 如果我以原始类型作为参数调用泛型方法,将使用什么类型参数?

java - Generic ObjectPool - 如何返回一个通用类?

java - 如何使用 Java 连接到 wifi 设备?

java - Firebase Firestore : How to convert document object to a POJO on Android

java - 如何检测文本是否包含 [FSI]*[PDI]

c - 为什么即使我在 C 中使用 "const"我的数据也没有受到保护?

java - 连接到远程数据库

arrays - 如何使用冒号运算符将半整数序列压缩为字符串表达式? (如何将列表转换为字符串)

ruby-on-rails - 如何从 Rails 中的 ActiveRecord 数组中提取 "table"?

java - 为什么不允许使用instanceof,但在泛型中允许使用Class.isInstance()?