开发者

Impossible null pointer

I have a real weird problem. (Very important note: this is an ex开发者_开发百科ample cause I can't paste the original code, I wrote it as text with no compiler.) I have 2 classes:

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;
   }
}

Now, sometimes I get the print... but I don't see how's that possible.

A is a serialized class, but yet I can't figure it out.


It's not possible, no. You'll get a type error in the definition of A.getB() when you try to compile it, and your definition of A.setB() looks dubious as well (shadows b).


There are a few circumstances in which b might be null:

  • reflection. b might be set to null reflectively, which circumvents your setter.
  • custom serialisation. b might be explicitly restored as null. Alternatively, if B is not serialisable, you have it marked as transient to avoid errors and it's not restored.

To verify a simple serialisation workflow, use the following code:

    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);

where the first line is replaced by the actual object you wish to test


If you manage to serialize an instance of A which has b == null, then you get a NPE. The reason is that during de-serialization, the constructor isn't invoked and therefore, private B b = new B(); isn't run, so b stays null.


Did you serialize the instance of A before adding the initialization of B to the class?
If that is the case you could get an instance of A where b is null because the constructors are not called (initializing a member of the class is part of the implicit constructor).
Then you will need to add an implementation of readObject() to class A there you can check whether or not b is null and initialize it if necessary.


This line won't compile either:

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


Well, what about this? If you give B as a parameter, why not use it?

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

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

   public B getB(){
       return b;
   }
}


Just an idea: replace

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

with

new Exception().printStackTrace();

That should make it easier for you to see what happened just before. Otherwise, without more information, the only things that seems a possible cause is the serialization.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜