为什么java允许这个?

时间:2011-05-03 12:31:12

标签: java syntax semantics

执行此操作在语法上是合法的:

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

o[0] = new Integer(42);

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

我的问题是:首先允许这项任务的重点是什么?

6 个答案:

答案 0 :(得分:8)

问题在于作业Object [] o = s; - 我认为你的意思是“这个”。

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

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

答案 1 :(得分:2)

允许这种任务的重点在于不允许这样做会使以下事情变得不可能:

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

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

如果编译器禁止你的字符串 - >对象的情况,那么它也必须禁止ArrayList - >列表以及从子类分配给其超类类型之一的任何其他实例。这种使面向对象语言(如Java)的许多功能变得毫无用处。当然,做这样的事情更为典型:

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

但无论如何,编译器无法在不同时禁用许多有用和合法的用例的情况下过滤掉这些情况,因此程序员需要确保他们正在做的事情是正确的。如果您想要的是Object[],那么请声明您的变量。如果您将某些内容声明为String[],请将其转换为Object[],然后忘记您实际拥有的是String[],那么这只是程序员错误。

答案 2 :(得分:1)

不允许,运行该代码时会得到java.lang.ArrayStoreException: java.lang.Integer

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

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

编译器没有抱怨,但是你在运行时得到了ClassCastExeption。

答案 3 :(得分:0)

编译器无法知道(没有静态分析)o实际上是String[],因此即使它在运行时失败也允许赋值。什么都没有阻止例如Integer[]被分配到o,但这不会发生。

答案 4 :(得分:0)

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

考虑一下:

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

o = new Integer[1];

o[0] = new Integer(1);

此情况有效且运行正常。为了提供更广泛的视角,IMHO Arrays是Java中的低级漏洞抽象。

答案 5 :(得分:0)

通常,编译器无法判断o是否已被指定为String[]。考虑一下:

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

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

o[0] = 42;

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