繁体   English   中英

行为差异:'null'初始化最终静态成员,'null'初始化最终局部变量

[英]Behaviour Difference: 'null' initialized final static member, and 'null' initialized final local variable

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

考虑一种情况:

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

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

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

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


很抱歉错过了之前:

我正在使用Eclipse Juno ,在Ubuntu 12.04上使用OpenJDK 7

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

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

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

哇! 原来,这是日食的具体问题。 当我使用以下代码编译代码时:

javac -Xlint:all Demo.java

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

Windows - > 首选项 - > Java - > 编译器 - > 错误/警告中 ,在Null Analysis下 ,我可以更改Eclipse编译器应该处理Null指针访问的方式。 我可以将其设置为 - 忽略错误警告

现在看来这是一个完全愚蠢的问题。 对我感到羞耻。 :(

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

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

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方法。 因此它逃脱了流分析(编译器不确定实例变量在该点是否为空,但在第一种情况下编译确保局部变量将始终为null)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM