26

在 Java 中摆弄时,我初始化了一个负长度的新字符串数组。IE -

String[] arr = new String[-1];

令我惊讶的是,编译器并没有抱怨它。谷歌搜索没有提出任何相关的答案。任何人都可以对这个问题有所了解吗?

非常感谢!

4

4 回答 4

25

原因是 JLS 允许这样做,而将其标记为编译错误的编译器将拒绝有效的 Java 代码。

它在JLS 15.10.1中指定。这是相关的片段:

“...如果任何 DimExpr 表达式的值小于零,则抛出 NegativeArraySizeException。”

现在,如果 Java 编译器将代码标记为错误,那么指定的行为就不会发生……在那个特定的代码中。

此外,在涉及编译时常量表达式(如-1. (谁能说这真的是一个错误?)


下一个问题当然是“为什么 JLS 允许这样做?”

您需要询问 Java 设计人员。但是我可以想到一些(大部分)合理的原因:

  • 这最初被忽略了,并且没有强有力的理由来修复它。(注意修复它会破坏源代码的兼容性。)

  • 它被认为太不寻常/边缘情况不值得处理。

  • 它可能会给编写源代码生成器的人带来问题。(想象一下,为了不生成不可编译的代码,必须编写代码来评估编译时常量表达式。使用当前的 JLS 规范,您可以简单地生成“坏”大小的代码,并处理如果代码被执行,则异常(或不异常)。)

  • 也许有人计划在 Java 中添加“unarrays” :-)


其他答案表明编译器可以/应该“标记”这种情况。如果“标记”意味着输出警告消息,那肯定是 JLS允许的。但是,编译器是否应该这样做是有争议的。一方面,如果上面的代码是错误编写的,那么标记该错误会很有用。另一方面,如果它不是错误(或“错误”不相关),那么警告将是噪音,或者更糟。无论哪种方式,这都是您需要与相应编译器的维护者讨论的问题。

于 2012-05-17T13:14:20.993 回答
2

我看不出为什么不能在编译时标记它(至少作为警告),因为它在执行时无条件地抛出NegativeArraySizeException

我用我的编译器做了一些快速的实验,对这种事情似乎出奇的放松。它不会发出关于常量表达式中整数除以零、使用常量索引的越界数组访问等的警告。

由此我得出结论,这里的一般模式是信任程序员。

于 2012-05-17T13:18:20.507 回答
1

编译器只负责检查语言的语法,而不是你代码的语义。因此,编译器没有抱怨错误是合理的,因为您的代码中根本没有语法错误。

在 Java 中,数组是在运行时分配的,这绝对没问题。如果是在编译时分配,那么编译器如何检查以下代码?

// runtime pass the length, with any value
void t(int length) {
   String[] stirngs = new String[length];
}

当将负值作为长度传递给构造数组时,将抛出运行时异常。

public class Main {

    public static void main(String[] args) {
        String[] v = new String[-1];
    }
}

有错误:

Exception in thread "main" java.lang.NegativeArraySizeException
    at Main.main(Main.java:5)
于 2012-05-17T13:26:28.590 回答
0

Java 编译器将整数作为数组的长度。它可以是变量或编译时常量。数组的长度是在创建数组时确定的。创建后,它的长度是固定的。

编译器应该将一个负的编译时常量标记为数组的长度。它只是不这样做。如果长度为负数,您将在运行时收到 NegativeArraySizeException。

于 2012-05-17T13:18:15.340 回答