【问题标题】:NPE is thrown at static class declarationNPE 在静态类声明中被抛出
【发布时间】:2014-07-01 07:10:37
【问题描述】:

我在一些静态类声明中遇到了一个奇怪的 NPE,我不知道为什么。

我有一个虚拟对象只是用来携带数据(是一个内部类),如下:

private static class MyStaticClass { //this is line 400
    private String a;
    private String b;
    private String c;
    private String d;

    private Boolean flag1 = Boolean.FALSE;
    private Boolean flag2 = Boolean.TRUE;
    private Boolean flag3 = Boolean.TRUE;
    private List<String> list = Collections.EMPTY_LIST;

    public MyStaticClass() {}

    public MyStaticClass(AnotherDataObject data) {
        a = data.getA();
        b = data.getB();
        c = data.getC();
        d = data.getD();
    }

}

客户端代码(MyClass.myMethod)如下所示:

public class MyClass {

    public void myMethod() {
        Map<Key, MyStaticClass> thisMap = new HashMap<Key, MyStaticClass>(DEFAULT_BUFFSIZE);

        //stuff

        for() {
            //stuff
            MyStaticClass instance = new MyStaticClass(value1, value2, value3);
            thisMap.put(generatedKey, instance);
        }

        //stuff

        for() { //every key
            MyStaticClass myStaticClassInstance = map.get(key); //this isn't null, i checked it.
            if(randomObject.flag && myStaticClassInstance.flag2) {
                //do stuff
            }
        }

        //more stuff
    }

    private static class MyStaticClass {
        //look the previous code snippet for more info
    }
}

现在,我有一个线性运行(无并发)的函数,并在某些时候评估下一句:

if(randomObject.flag && myStaticClassInstance.flag2) //randomObject is another class

当 JVM 评估这句话时,在 MyStaticClass 声明(私有静态类...)处抛出 NPE,我不知道为什么。

没有静态块,flag2 永远不会设置为 null。

假设在第 400 行声明了“静态类 MyStaticClass”。所以,堆栈跟踪是这样的:

java.lang.NullPointerException
    at org.mypackage.MyClass$MyStaticClass.access$1300(MyClass.java:400)
    at org.mypackage.MyClass.myMethod(MyClass.java:283)
    at org.mypackage.AsyncDestination$1.run(AsyncDestination.java:102)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)

编辑:我添加了一个简单的测试,使用 MyStaticClass 作为 null (https://gist.github.com/anonymous/35b94fea2a993fc350e4),异常类似,但它被抛出在属性声明行,而不是声明类的行。

【问题讨论】:

  • 为什么不把这些字段设为静态?
  • private static 的类并没有什么特别之处,你得到一个 NPE 只是因为你取消了 null 的引用,就像代码中的其他任何地方一样。我建议你断点这段​​代码并在你的调试器中检查它。
  • @ScaryWombat 因为它实际上不是静态的。只是一个内部类。
  • @PeterLawrey myStaticClassInstance 是一个对象。假设我在第 400 行声明了静态类。堆栈跟踪表明 NPE 在第 400 行抛出 MyClass$MyStaticClass.access$1300。 .access 属性是什么?
  • private static 有什么特殊原因,如果你有 private 类,你想从哪里访问它?

标签: java static nullpointerexception


【解决方案1】:

在声明可能是原语的字段时,您应该问自己这个问题;这应该是null 还是不是。如果该值可以为 null,则可以使用包装器或毒丸值。但是,字段不应该是null,如果可以避免的话,您不应该使用包装器。使用原语不仅会更快,而且值不能是null也更清楚

在回答您的问题时,您将获得 NPE,因为您的值是 null 使用 private static class 不会改变这一点。我建议你断点你的代码并在你的调试器中查看它。

堆栈跟踪表明 NPE 在第 400 行抛出 MyClass$MyStaticClass.access$1300。 .access 属性是什么?

使用私有字段和类可能会造成混淆,因为 JVM 实际上并不像 Java 那样支持访问私有成员。编译器生成代码以允许此访问,从而产生访问器方法。

从异常来看,最可能的解释是flag2是null

所以我建议

  • 使用调试器查看发生了什么。
  • 可以使用原语
  • 如果成员在其他类中被访问,则将您的访问包设为本地而不是私有。

【讨论】:

  • 我试试看。无论如何,我认为我面临一些奇怪的上下文问题或 JVM 错误。从 Quartz 任务启动事件或从 Web 线程启动它(事件由同一个事件处理程序线程处理),得到不同的结果。从 Quartz 创建的事件失败并出现此异常。从网络线程创建的事件,运行成功。
  • @SamuelGarcía 更好地理解问题的唯一方法是调试它。您可以在此行之前和之后添加日志记录/打印以查看值。
  • 只要你说“JVM bug”,实际上你的意思是“我不明白的东西”。在调查问题时,不要去那里。您必须竭尽全力希望这是您自己做错的事情,以便您可以解决它。
  • 你是对的,这就是为什么我首先说“一些奇怪的上下文问题” :) 我认为当事件从 Quartz 作业中触发时我做错了,即使事件已被处理由同一个线程和同一个工人,尽管它的起源。
  • 我已经切换到 live env 中的原语。到目前为止它一直有效。不过,我不知道为什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-28
  • 1970-01-01
  • 2015-12-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多