Java: когда добавить readObjectNoData () во время сериализации?
Я читаю главу сериализации в "эффективной 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;
}
}
И классный работник, который его расширяет.
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;
}
}
Существуют ли инварианты в классе персон, который я создал ? Когда они будут нарушены ? Я скопировал вставленный код для метода readObjectData () в класс Employee, но он так и не получил называемый. Когда будет вызван метод readObject ()? Я что-то упустил ?
4 ответов:
Раздел readObjectNoData в спецификации сериализации объектов Java кажется интересным (см. ниже).
Ваши правки в вопросе дают прекрасный пример. ЕслиEmployeeбылserialized, когда он не расширялсяPersonи позжеdeserialized, когда это произошло, то частьPersonбудет инициализирована пустой строкой и 0 возрастом. Используя этот метод, вы можете инициализировать их в " имя " и 1 соответственно.Для сериализуемых объектов метод readObjectNoData допускает класс к управлять инициализацией собственных полей в том случае, если экземпляр подкласса десериализуется, и поток сериализации делает это не перечислять рассматриваемый класс как суперкласс десериализованного класса. объект. Это может произойти в тех случаях, когда получающая сторона использует другая версия класса десериализованного экземпляра, чем отправляющая сторона, а версия получателя расширяет классы, которые не являются расширено версией отправителя. Это также может произойти, если поток сериализации было подделано; следовательно, readObjectNoData является полезно для правильной инициализации десериализованных объектов, несмотря на "враждебный" или неполный исходный поток.
Каждый сериализуемый класс может определить свой собственный метод readObjectNoData. Если сериализуемый класс не определяет метод readObjectNoData, то в обстоятельствах, перечисленных выше, поля класса будут инициализируются до значений по умолчанию (как указано в разделе 4.5.5 Язык JavaTM Спецификация, второе издание); это поведение является согласуется с тем, что ObjectInputStream до версии 1.4 JavaTM 2 SDK, Standard Edition, когда поддержка readObjectNoData методы были введены. Если сериализуемый класс определяет метод readObjectNoData и вышеупомянутые условия возникают, то readObjectNoData будет вызвана в точке во время десериализации когда класс определен метод readobject иначе можно назвать было класс, о котором идет речь, был перечисляется потоком как суперкласс экземпляр десериализуется.
private void readObjectNoData() throws ObjectStreamException;
Существуют ли инварианты в классе персон, который я создал? Когда они будут нарушены?
Нет явно, но представьте, что другие методы в классе предполагают, что
nameникогда не являетсяnullи бросил быNullPointerException, если бы это когда-либо было. В этом случае ненулевое значениеnameявляется инвариантом.Я скопировал код для метода
readObjectData()в классеEmployee, но он так и не был вызван. Когда будет вызван методreadObject()?Нет никакого метода
readObjectData()это, должно быть, опечатка, связанная с сериализацией. МетодreadObject()вызывается каждый раз, когда сериализованный объект десериализуется.Метод
readObjectNoData()используется для некоторого неясного углового случая при десериализации подклассакласса, содержащего метод.Статьяadvanced serialization на веб-сайте
SunOracle описывает назначение этих вспомогательных методов сериализации. Я предлагаю вам начать там и разместить любые последующие вопросы, которые вы можете встречать.(обновление)
Если вам интересно, метод readObjectNoData был добавлен в выпуске 1.4 для покрытия углового случая, связанного с добавлением сериализуемого суперкласса к существующему сериализуемому классу. Подробности можно найти в спецификации сериализацииSerialization, 3.5 .
Текст ссылки:
Для сериализуемых объектов метод readObjectNoData позволяет классу управлять инициализацией его собственные поля в том случае, если экземпляр подкласса десериализуется и поток сериализации не перечисляет рассматриваемый класс как суперкласс десериализуемого объекта. Это может произойти в тех случаях, когда получающая сторона использует другую версию класса десериализованного экземпляра, чем отправляющая сторона, и версия получателя расширяет классы, которые не расширяются версией отправителя. Это также может произойти, если поток сериализации был изменен; следовательно, readObjectNoData является полезно для правильной инициализации десериализованных объектов, несмотря на "враждебный" или неполный исходный поток.
Таким образом, это может произойти в двух случаях:
JVM, который декодирует поток объектов, имеет более новую версию десериализуемого подкласса (
Employee), которая расширяет некоторый родительский класс (Person). JVM, который первоначально кодировал поток объектов, имеет другую, более старую версию этих классов, гдеPersonеще не был суперклассомEmployee.- кто-то намеренно испортил поток объектов, чтобы сломать вещи.
"расширяемый" означает "может иметь подкласс".
ReadObjectNoData используется в необычном случае, когда сериализатор (writer) работает с версией класса без базового класса, в то время как десериализатор (reader) класса имеет версию класса, основанную на подклассе. Подкласс может сказать: "это нормально, если мой базовый класс не находится в сериализованных данных - просто сделайте пустой", реализуя readObjectNoData. Смотрите эти заметки о выпуске .
Инвариантом в вашем классе Person может быть что-то вроде:
age must be greater than 0Итак, когда класс Person создается со значением по умолчанию 0 (см. здесь: http://download.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html ) вы нарушите этот инвариант.
Однако, учитывая конструктор по умолчанию, вы будете в порядке :)
Comments