Подтвердить что ты не робот

Java: Когда добавлять readObjectNoData() во время сериализации?

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

Если вы реализуете класс с полями экземпляров, которые сериализуются        и расширяемость, есть предостережение, о котором вы должны знать. Если класс        имеет инварианты, которые будут нарушены, если его поля экземпляра мы        инициализируются значениями по умолчанию (ноль для интегральных типов,        false для boolean и 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()? Я что-то пропустил?

4b9b3361

Ответ 1

Раздел readObjectNoData в спецификации Java Object Serialization кажется интересным (см. ниже).

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

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

private void readObjectNoData() throws ObjectStreamException;

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

Ответ 2

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

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

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

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

Метод readObjectNoData() попадает в какой-то неясный краевой случай при десериализации подкласса класса, который содержит этот метод.

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

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

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

Написанный текст:

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

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

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

Ответ 3

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

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

Ответ 4

Инвариант в вашем классе Person может быть примерно таким:

age must be greater than 0

Итак, когда экземпляр класса Person создается со значением по умолчанию 0 (см. здесь: http://download.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html), вы нарушите этот инвариант.

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