2009-10-08 2 views
-5

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

+1

Перед каждой строкой в ​​коде добавьте четыре пробела. Это отобразит его как код. – Imagist

+2

Этот код не компилируется. Отправьте пример, который будет компилировать и демонстрировать ошибку воспроизводимо. – Bombe

+0

Код еще не компилируется. Например, getB() возвращаемый тип должен быть B: public B getB() –

ответ

5

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

+0

Не говоря уже о ошибке типа в A.setB(). – starblue

+0

Действительно, должно быть 'this.b.setNum (b! = Null? B.getNum(): 8);' - Я почти добавил это как ответ, вы должны сказать это более четко. – Kobi

+0

Опять же, это пример кода. Не настоящий код. – Udi

0

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

b.setNum(b != null? b.getNum : new B()); 
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; 
    } 
} 
+0

причина Я не хочу, чтобы b когда-либо был null .. – Udi

+0

Это никогда не пусто! Вы назначили новый B(); – user181750

+0

a.setB (null) приведет к тому, что b будет недействительным в вашем коде – Udi

2

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

1

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

+0

Вы действительно имеете в виду 'readResolve'? 'readObject' будет делать так, как' b' не является окончательным. –

+0

Вы правы, readObject будет делать - я обновил ответ. – Turismo

3

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

  • отражение. b может быть настроен на нулевое отражение, что обходит ваш сеттер.
  • пользовательская сериализация. 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); 

, где первая строка заменяется на реальный объект, который вы хотите проверить

+0

вы уверены, что рефлексия «пропускает» сеттеры? потому что он не пропускает конструктор по умолчанию, насколько я знаю. – Udi

+1

Отражение не вызывает никаких сеттеров. Кроме того, правила вызова конструктора немного сложнее. Правило (IIRC) заключается в том, что если у вас есть иерархия классов, которая содержит классы «Serializable» и «non-'Serializable», все конструкторы несериализуемых классов будут * не * работать. –

+0

Хорошо. Итак, есть ли какой-нибудь ват для меня, чтобы проверить, что проблема вызвана отражением? Я имею в виду любой метод, чтобы переопределить ..? Или отражение напрямую меняет поля? – Udi

0

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

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

с

new Exception().printStackTrace(); 

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

+0

Или 'Thread.dumpStack();'. –

Смежные вопросы