Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么java允许这样做?_Java_Syntax_Semantics - Fatal编程技术网

为什么java允许这样做?

为什么java允许这样做?,java,syntax,semantics,Java,Syntax,Semantics,这样做在语法上是合法的: String [] s = new String[1]; Object [] o = s; o[0] = new Integer(42); 但它当然会在运行时崩溃 我的问题是:首先允许这个赋值有什么意义?编译器无法知道(没有静态分析)o实际上是一个String[],因此即使在运行时失败也允许赋值。没有什么可以阻止将例如Integer[]分配给o,它就是不会发生。这是不允许的,当您运行该代码时,您会得到一个java.lang.ArrayStoreException:j

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

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

o[0] = new Integer(42);
但它当然会在运行时崩溃


我的问题是:首先允许这个赋值有什么意义?

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

这是不允许的,当您运行该代码时,您会得到一个
java.lang.ArrayStoreException:java.lang.Integer

编译器允许这样做,因为您正在将字符串[]强制转换为对象[],这是正确的。这类似于

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

编译器不会抱怨,但您在运行时会得到一个ClassCastExection。

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

考虑这一点:

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

o = new Integer[1];

o[0] = new Integer(1);
String[] s = new String[1];
Object[] o;

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

o[0] = 42;

此情况有效,运行正常。从更广阔的角度来看,IMHO数组在Java中是一种低级的泄漏抽象。

问题在于赋值
对象[]o=s-我想这就是你所说的“这个”的意思

技术术语是,没有它,就不可能有处理数组的通用代码。例如,
java.util.array
中的大多数非基本数组方法都是无用的,因为您只能将它们用于实际的
Object[]
实例。显然,Java设计者认为这比完整的类型安全更重要


有一种替代解决方案,您可以在查看Java5中引入的Java泛型时看到:通过通配符的显式协方差。然而,这会导致相当多的复杂性增加(参见关于
通配符的问题不断),Java的原始设计者希望避免复杂性。

允许这种分配的意义在于,不允许它会使以下情况变得不可能:

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

List[] genericLists = lists;
lists[0].add("someObject");
如果编译器禁止字符串->对象大小写,那么它还必须禁止ArrayList->List和任何其他从子类分配到其超类类型的实例。这使得像Java这样的面向对象语言的许多特性变得毫无用处。当然,更典型的做法是:

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

但无论如何,编译器不能在不同时禁止许多有用和合法的用例的情况下过滤掉这些用例,因此,由程序员来确保他们所做的是合理的。如果您想要的是一个
对象[]
,那么就这样声明您的变量。如果将某个对象声明为
String[]
,将其强制转换为
对象[]
,然后忘记您真正拥有的是
字符串[]
,那么这只是程序员的错误。

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

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

o = new Integer[1];

o[0] = new Integer(1);
String[] s = new String[1];
Object[] o;

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

o[0] = 42;

编译器在设计时不知道将采用什么类型的
o
,因此它只允许赋值。

但您根本没有回答这个问题。你只不过是在陈述OP所说的。此外,OP从未说过它是“允许的”,OP说它在“语法”上是正确的,并且在运行时崩溃了。OP精心设计的问题非常清楚,您的答案没有回答任何问题……我只是说明编译器不会通过显示与对象的类比来生成错误或警告。更重要的是,ArrayStoreException在为数组赋值时相当于ClassCastExeception,因为当类型不兼容时会抛出这些值。但请随意不同意:)。