Java: когда добавлять readObjectNoData () во время сериализации? - PullRequest
22 голосов
/ 16 сентября 2011

Я читаю главу сериализации в "Эффективной Java".Я пытаюсь понять нижеследующий абзац в книге.

Если вы реализуете класс с полями экземпляров, которые сериализуются и расширяются, есть предостережение, о котором вам следует знать.Если у класса есть инварианты, которые были бы нарушены, если бы его поля экземпляра были инициализированы их значениями по умолчанию (ноль для целочисленных типов, false для логических типов и null для ссылочных типов объектов), необходимо добавить этот метод readObjectNoData в класс:

    // readObjectNoData for stateful extendable serializable classes
     private void readObjectNoData() throws InvalidObjectException {
             throw new InvalidObjectException("Stream data required");
     }

Я не уверен, что означает вышеупомянутая оценка.

Чтобы проверить это, я создал класс Person (как сериализуемый, так и расширяемый)

   class Person   implements Serializable{

       private String name;

       private int age;

      Person() {
         this("default",1);
      }


     Person(String name, int y) {
       this.name = name;
        this.age = y;
      }
    }

икласс Employee, расширяющий его.

     class Employee extends Person  {

      String address ;


    public Employee()
    {
        super();
        address ="default_address";
    }

    public Employee(String name , int age, String address)
    {
        super(name,age);
        this.address = address;
    }
           }

Существуют ли инварианты в созданном мною классе Person?Когда они будут нарушены?Я скопировал и вставил код для метода readObjectData () в класс Employee, но он так и не был вызван.Когда будет вызван метод readObject ()?Я что-то упустил?

Ответы [ 4 ]

22 голосов
/ 16 сентября 2011

Раздел readObjectNoData в Спецификации Сериализации Объекта Java представляется интересным (см. Ниже).

Ваши изменения в вопросе дают прекрасный пример.Если бы Employee было serialized, когда оно не расширилось Person, а позже deserialized, когда это произошло, то часть Person была бы инициализирована пустой строкой и 0 возрастом.Используя этот метод, вы можете инициализировать их как «имя» и 1 соответственно.

Для сериализуемых объектов метод readObjectNoData позволяет классу управлять инициализацией его собственных полей в случае десериализации экземпляра подкласса, и поток сериализации не перечисляет рассматриваемый класс как суперклассдесериализованного объекта.Это может происходить в тех случаях, когда принимающая сторона использует версию десериализованного экземпляра, отличную от отправляющей стороны, а версия получателя расширяет классы, которые не расширяются версией отправителя.Это также может произойти, если поток сериализации был подделан;следовательно, readObjectNoData полезен для правильной инициализации десериализованных объектов, несмотря на «враждебный» или неполный исходный поток.

private void readObjectNoData() throws ObjectStreamException;

Каждый сериализуемый класс может определять свой собственный метод readObjectNoData.Если сериализуемый класс не определяет метод readObjectNoData, то в перечисленных выше обстоятельствах поля класса будут инициализированы в их значения по умолчанию (как указано в разделе 4.5.5 в Спецификации языка JavaTM, второе издание);это поведение соответствует поведению ObjectInputStream до версии 1.4 JavaTM 2 SDK Standard Edition, когда была представлена ​​поддержка методов readObjectNoData.Если сериализуемый класс действительно определяет метод readObjectNoData и возникают вышеупомянутые условия, тогда readObjectNoData будет вызываться в точке во время десериализации, когда в противном случае будет вызван определяемый классом метод readObject, если рассматриваемый класс будет указан потоком как суперклассэкземпляр десериализован.

3 голосов
/ 16 сентября 2011

«Расширяемый» означает «может иметь подкласс».

readObjectNoData используется в необычном случае, когда сериализатор (писатель) работает с версией класса без базового класса, тогда как десериализатор (читатель) класса имеет версию класса, основанную на ISна подклассе.Подкласс может сказать «все в порядке, если мой базовый класс отсутствует в сериализованных данных - просто создайте пустой» путем реализации readObjectNoData.См. Эти заметки о выпуске .

3 голосов
/ 16 сентября 2011

Существуют ли инварианты в созданном мною классе Person?Когда они будут нарушены?

Нет явно, но представьте, что другие методы в классе предполагают, что name никогда не бывает null и будут выдавать NullPointerException, если это когда-либо было.В этом случае ненулевое значение name является инвариантом.

Я скопировал код для метода readObjectData() в классе Employee, но он никогда не вызывался.Когда будет вызван метод readObject()?

Нет метода readObjectData(), связанного с сериализацией, это должна быть опечатка.Метод readObject() вызывается каждый раз, когда сериализованный объект десериализуется.

Метод readObjectNoData() используется для неясного углового случая при десериализации подкласса класса, содержащего метод.

расширенная сериализация статья на веб-сайте Oracle Sun описывает назначение этих вспомогательных методов сериализации.Я предлагаю вам начать там и публиковать любые последующие вопросы, с которыми вы можете столкнуться.

(обновление)

Если вам интересно, метод readObjectNoData был добавлен в выпуске 1.4 для покрытияугловой случай, включающий добавление сериализуемого суперкласса к существующему сериализуемому классу.Подробности можно найти в спецификации сериализации Сериализация, 3.5 .

Ссылочный текст:

Для сериализуемых объектов метод readObjectNoData позволяеткласс для управления инициализацией его собственных полей в случае десериализации экземпляра подкласса, и поток сериализации не перечисляет рассматриваемый класс как суперкласс десериализованного объекта.Это может происходить в тех случаях, когда принимающая сторона использует версию десериализованного экземпляра, отличную от отправляющей стороны, а версия получателя расширяет классы, которые не расширяются версией отправителя.Это также может произойти, если поток сериализации был подделан;следовательно, readObjectNoData полезен для правильной инициализации десериализованных объектов, несмотря на «враждебный» или неполный исходный поток.

Так что это может произойти в двух случаях:

  • JVM, которая декодируетпоток объектов имеет более новую версию десериализованного подкласса (Employee), который расширяет некоторый родительский класс (Person).JVM, которая первоначально * en * кодировала поток объектов, имеет другую, более старую версию этих классов, где Person еще не был суперклассом Employee.
  • Кто-то преднамеренно перепутал с потоком объектов в порядкесломать вещи.
0 голосов
/ 16 сентября 2011

Инвариант в вашем классе Person может иметь виднарушил этот инвариант.

Однако, учитывая конструктор по умолчанию, у вас все будет хорошо:)

...