Невозможный нулевой указатель - PullRequest
0 голосов
/ 08 октября 2009

У меня настоящая странная проблема.(Очень важное примечание: это пример, потому что я не могу вставить оригинальный код, я написал его как текст без компилятора.) У меня есть 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 ]

5 голосов
/ 08 октября 2009

Это невозможно, нет. Вы получите ошибку типа в определении A.getB() при попытке его скомпилировать, и ваше определение A.setB() также выглядит сомнительным (тени b).

3 голосов
/ 08 октября 2009

Есть несколько обстоятельств, при которых b может быть нулевым:

  • отражение. b может быть равно нулю, что обходит ваш сеттер.
  • Пользовательская сериализация. b может быть явно восстановлено как ноль. Кроме того, если 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 голосов
/ 08 октября 2009

Если вам удастся сериализовать экземпляр A с b == null, вы получите NPE. Причина в том, что во время десериализации конструктор не вызывается, и поэтому private B b = new B(); не запускается, поэтому b остается null.

1 голос
/ 08 октября 2009

Сериализовали ли вы экземпляр A перед добавлением инициализации B в класс?
Если это так, вы можете получить экземпляр A, где b равно нулю, поскольку конструкторы не вызываются (инициализация члена класса является частью неявного конструктора).
Затем вам нужно будет добавить реализацию readObject () в класс А. Там вы можете проверить, является ли b нулевым, и инициализировать его, если необходимо.

0 голосов
/ 08 октября 2009

Просто идея: заменить

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

с

new Exception().printStackTrace();

Это должно помочь вам увидеть то, что произошло прямо перед этим. В противном случае без дополнительной информации единственной вещью, которая кажется возможной причиной, является сериализация.

0 голосов
/ 08 октября 2009

Ну, а как насчет этого? Если вы даете B в качестве параметра, почему бы не использовать его?

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

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

   public B getB(){
       return b;
   }
}
0 голосов
/ 08 октября 2009

Эта строка также не будет компилироваться:

b.setNum(b != null? b.getNum : new B());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...