繁体   English   中英

为什么 java 允许这样做?

[英]why does java allow this?

这样做在语法上是合法的:

String [] s = new String[1];
Object [] o = s;

o[0] = new Integer(42);

但当然它会在运行时崩溃。

我的问题是:首先允许这项任务有什么意义?

问题是赋值Object [] o = s; - 我想这就是你所说的“这个”。

技术术语是数组协方差,如果没有它,您将无法拥有处理 arrays 的代码。 例如, java.util.Arrays中的大多数非原始数组方法都是无用的,因为您只能将它们与实际的Object[]实例一起使用。 显然,Java 的设计者认为这比完整的类型安全更重要。

当您查看在 Java 5 中引入的 Java 的 generics 时,您会看到另一种解决方案:通过通配符显式协方差。 但是,这会导致相当大的复杂性(请参阅关于?通配符的问题的常量 stream),Java 的原始设计者希望避免复杂性。

允许这种分配的重点是不允许它会使以下事情变得不可能:

ArrayList[] lists = new ArrayList[10];
lists[0] = new ArrayList();

List[] genericLists = lists;
lists[0].add("someObject");

如果编译器禁止您的 String -> Object 情况,那么它还必须禁止 ArrayList -> List 以及从子类分配给其超类类型之一的任何其他实例。 这使得诸如 Java 之类的面向对象语言的许多特性变得毫无用处。 当然,更典型的做法是:

List[] lists = new List[10];
lists[0] = new ArrayList();
lists[0].add("someObject");

但无论如何,编译器无法过滤掉这些情况,同时不允许许多有用且合法的用例,因此程序员有责任确保他们所做的事情是理智的。 如果你想要的是一个Object[] ,那么就这样声明你的变量。 如果您将某些内容声明为String[] ,将其转换为Object[] ,然后忘记您真正拥有的是String[] ,那么这只是程序员错误。

这是不允许的,运行该代码时会出现java.lang.ArrayStoreException: java.lang.Integer

编译器允许这样做,因为您将 String[] 转换为 Object[],这是正确的。 这类似于

Integer i = new Integer(10);
Object o = i;
String s = (String) o;

编译器不会抱怨,但您会在运行时获得 ClassCastExeption。

编译器无法知道(没有 static 分析) o实际上是一个String[] ,因此即使它在运行时失败也允许赋值。 没有什么可以阻止将例如Integer[]分配给o ,它只是不会发生。

必须允许赋值,因为编译器无法推断数组在运行时是否只保存(或不保存)字符串。 它抛出一个[ArrayStoreException][1]在运行时检查。

考虑一下:

String [] s = new String[1];
Object [] o = s;

o = new Integer[1];

o[0] = new Integer(1);

这种情况是有效的并且运行正常。 为了提供更广泛的视角,恕我直言,Arrays 是 Java 中的低级泄漏抽象。

通常,编译器无法判断o是否已分配为String[] 考虑一下:

String[] s = new String[1];
Object[] o;

if (complexFunction(System.currentTimeMillis())) {
  o = s;
} else {
  o = new Integer[1];
}

o[0] = 42;

编译器在设计时不会知道o将采用什么类型 - 所以它只允许赋值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM