[英]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.