为什么 Java 允许类型不安全的数组赋值?

通常,Java可以被认为是一种类型安全的语言。我知道泛型有一些缺陷,但我最近遇到了一个我以前从未遇到过的问题。要分解它:

Object[] objects = new Integer[10];
objects[0] = "Hello World";

不会按预期导致编译时错误。我假设 Array of 的声明将不允许指向其他事物的数组。在泛型中,我不允许做这样奇怪的事情:Object

ArrayList<Object> objs = new ArrayList<Integer>

如果我试图欺骗Java做一些事情

ArrayList<? extends Object> objects = new ArrayList<Integer>

我被允许声明它,但我只能添加 类型的对象。null

为什么Java不阻止这种被篡改的数组的声明呢?


答案 1

首先,我应该指出这是类型安全的。

Object[] objects = new Integer[10];
objects[0] = "Hello World";

因为将引发异常。(它不是静态类型安全的...但这是完全不同的陈述。

Java允许这样做的原因是历史性的。在Java 5之前,Java不支持任何形式的泛型。Gosling曾说过,如果他们有时间弄清楚并将泛型合并到Java 1.0中,他们就会这样做。

不幸的是,他们没有。但他们仍然希望能够编写诸如具有以下签名的通用排序方法之类的东西:

    void sort(Object[] array, Comparator comp) ...

为了使此方法适用于任何类型的对象数组(没有泛型),有必要使数组协变;即,使在形式类型为 .如果他们没有这样做,你将不得不将 复制到 一个 ,对它进行排序,然后将其复制回来。String[]Integer[]Object[]String[]Object[]


答案 2

我不认为除了“传统设计”之外,还有答案。(我承认这是一种说“因为”的花哨方式。你几乎需要能够以某种方式完成你展示的最后一个任务的等效任务。(否则,你就习惯于用手动上/下转换制作大量副本,假设Java 1.4之前的语言特性)

在Java 1中,当数组的类型语义基本上是一成不变的,泛型不可用,甚至在很长一段时间内都没有考虑。因此,没有可用的机制来表达使这种构造类型安全所需的高阶类型约束 - 并且Gosling(IIRC是简单的粉丝)认为解决编译时类型安全性的边缘情况不值得用任何可用的解决方案使语言复杂化。或者没有因为在运行时进行检查而烦恼,甚至无法寻找解决方案。(归根结底,语言设计决策至少在某种程度上是任意的,只有一个人可以肯定地回答这个问题。