不可能的空指针

时间:2009-10-08 08:14:30

标签: java nullpointerexception

我有一个非常奇怪的问题。 (非常重要的说明:这是一个例子,因为我无法粘贴原始代码,我将其编写为没有编译器的文本。)我有2个类:

class B {
    private int num = 9;

    public int getNum(){
       return num;
    }

    public void setNum(int num){
       this.num = num;
    }
}

class A {
    private B b = new B();

    public void setB(B b){
        b.setNum(b != null? b.getNum() : 8);
   }

   public B getB(){
       if (b == null)
           System.out.println("How possible?");
       return b;
   }
}

现在,有时我会得到印刷品......但我不知道那是怎么回事。

A是一个序列化的类,但我无法弄明白。

7 个答案:

答案 0 :(得分:5)

这是不可能的,不。当您尝试编译时,A.getB()的定义会出现类型错误,而A.setB()的定义看起来也很可疑(阴影b)。

答案 1 :(得分:3)

在某些情况下b可能为null:

  • 反射。 b可能会被反射设置为null,从而绕过你的二传手。
  • 自定义序列化。 b可能会显式恢复为null。或者,如果B不可序列化,则将其标记为瞬态以避免错误并且不会恢复。

要验证简单的序列化工作流程,请使用以下代码:

    Object object = "someString";

    ByteArrayOutputStream holder = new ByteArrayOutputStream();
    new ObjectOutputStream(holder).writeObject(object);

    Object readObject = new ObjectInputStream(new ByteArrayInputStream(holder.toByteArray())).readObject();

    System.out.println(readObject);

其中第一行被您要测试的实际对象替换

答案 2 :(得分:2)

如果您设法序列化具有A的{​​{1}}实例,那么您将获得一个NPE。原因是在反序列化期间,未调用构造函数,因此b == null未运行,因此private B b = new B();保持b

答案 3 :(得分:1)

在将B的初始化添加到类之前,您是否序列化了A的实例? 如果是这种情况,您可以获得A的实例,其中b为null,因为未调用构造函数(初始化类的成员是隐式构造函数的一部分)。
然后你需要在类A中添加readObject()的实现,你可以检查b是否为null并在必要时初始化它。

答案 4 :(得分:0)

此行不会编译:

b.setNum(b != null? b.getNum : new B());

答案 5 :(得分:0)

那么,这个怎么样?如果您将B作为参数,为什么不使用它呢?

class A {
    private B b = new B();

    public void setB(B b){
        if(b != null) {
            this.b = b;
        }
   }

   public B getB(){
       return b;
   }
}

答案 6 :(得分:0)

只是一个想法:替换

System.out.println("How possible?");

new Exception().printStackTrace();

这应该让您更容易看到之前发生的事情。否则,没有更多信息,唯一可能的原因是序列化。