java - 行为差异 : 'null' initialized final static member, 和 'null' 初始化最终局部变量

标签 java compiler-warnings final static-members local-variables

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

考虑第一个st案例:

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

正如预期的那样,编译器在 strnull 时向我显示以下警告 - Null pointer access: The variable str can only be null at这个位置。

现在,当我移动该变量时,static 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 中指定,所以我浏览了主题明确赋值,但没有找到与此问题相关的任何内容。谁能解释行为的变化? 如果可能的话,我正在寻找一些指向 JLS 的链接的强项?

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


很抱歉之前错过了:

我在 Ubuntu 12.04OpenJDK 7 上使用 Eclipse Juno

最佳答案

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

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

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

关于java - 行为差异 : 'null' initialized final static member, 和 'null' 初始化最终局部变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18017786/

相关文章:

java - Java 中类的“final”修饰符

java - 识别霍夫曼编码算法中字符的位置

java - CoreNLP MaxentTagger 架构选项 - 含义和有效性

java - 错误: local variable imagesLabel is accessed from within inner class; needs to be declared final (Java)

c++ - 禁用局部变量的未初始化警告

c++ - C26486 - 不要将可能无效的指针传递给函数?

java - 最终字段而不是枚举中的访问器

java - Spring @scheduled 带有 cron 但没有重叠的 cron

java - 在实例化/声明时指定类的父类(super class)型?

c - 如何从 Visual Studio C 编译器获得更有用的警告?