14

我在后续代码中遇到了一种我之前不知道的行为。

考虑第一种情况:

public static void main(String[] args) {    
    final String str = null;
    System.out.println(str.length());  // Compiler Warning: NullPointerAccess
}

str正如预期的那样,编译器向我显示以下关于为的警告-空指针访问:变量 str 在此位置只能为空。

现在,当我移动该变量时,静态 final 字段初始化为null

class Demo {
    static final String str = null;

    public static void main(String[] args) {
        System.out.println(str.length());  // No Compiler Warning
    }
}

现在,编译器没有显示任何警告。AFAIK,编译器应该知道,str最终,在代码的任何时候都不会改变它的值。鉴于它是null,肯定会在NullPointerException以后产生,它确实如此。

虽然,编译器在第一种情况下成功地警告了我,但为什么它在第二种情况下无法识别。为什么会发生这种行为变化?行为是相同的,如果我将static字段更改为instance字段,并使用Demo.

我认为这种行为可能已在 JLS 中指定,因此我浏览了主题Definite Assignment,但没有找到与此问题相关的任何内容。谁能解释行为的变化?如果可能的话,我正在寻找一些与 JLS 的链接的强项?

除此之外,为什么编译器首先只向我显示警告,因为我认为出于与上述相同的原因,方法调用肯定会在运行时抛出NPE,因为该字段无法更改?为什么它不向我显示编译器错误?我是否对编译器期望过高,因为它似乎很明显,运行时结果str.length()不能是什么NPE


很抱歉之前错过了:

我在Ubuntu 12.04上使用Eclipse JunoOpenJDK 7

4

3 回答 3

2

哇!事实证明,这是日食特定的问题。当我使用以下代码编译代码时:

javac -Xlint:all Demo.java

对于任何情况,它都没有显示任何警告。所以,我回到 eclipse 检查为这种情况启用的任何设置,并找到了一个。

Windows -> Preferences -> Java -> Compiler -> Errors/Warnings中,在Null Analysis下,我可以更改Eclipse Compiler 处理Null Pointer Access的方式。我可以将其设置为 - IgnoreErrorWarning

现在这似乎是一个完全愚蠢的问题。真丢人。:(

于 2013-08-02T16:27:04.970 回答
2

我不确定 100%,但是在第二种情况下,你有针对局部变量的 final 字段,有可能在静态(或实例块,取决于变量是否为静态)初始化块中直接为这个 final 字段分配一些值:

class Demo {
...
static {
 str = "some text";
}
...
}

所以编译器不会给你警告。

于 2013-08-02T13:25:49.320 回答
1
public static void main(String[] args) {    
    final String str = null;
    System.out.println(str.length());  // Compiler Warning: NullPointerAccess
}

在这种情况下 str 是一个局部变量,如果您在初始化它之前尝试对其执行任何操作,编译器将不会编译。流分析完全不同,它会检查代码流,在其中检测到在您执行 length() 操作时局部变量 str 只能为空。

class Demo {
    static final String str = null;

    public static void main(String[] args) {
        System.out.println(str.length());  // No Compiler Warning
    }
}

在这种情况下 str 是一个实例变量,即使您没有明确分配它也会为 null。

还是为什么这里没有警告?

您可以在构造函数中初始化实例变量。或者,您可以在对其调用 lenght() 操作之前对其调用 setter 方法。所以它从流分析中逃脱(编译器不确定实例变量在那时是否为空,但在第一种情况下,编译确定局部变量将始终为空)。

于 2013-08-02T13:20:52.927 回答