Моделирование экстернализации Java-объектов с помощью настраиваемой сериализации
Основное преимущество экстернализации по сравнению с сериализацией заключается в том, что экстернализация сохраняет только часть объекта, а не весь объект, как в случае сериализации. Но я думаю, что мы можем симулировать экстернализацию через пользовательскую сериализацию, если не будем вызывать метод defaultWriteObject() объекта ObjectOutputStream в методе writeObject() класса serializable. Поэтому, не вызывая метод defaultWriteObject() и сохраняя только необходимые переменные экземпляра сериализуемого класса в методе writeObject(), мы можем добиться преимуществ экстернализации.
Вот пример, демонстрирующий вышеупомянутые вещи:
package com.test;
import java.io.*;
public class Test {
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
Dog dog = new Dog();
System.out.println("before serialization: i = " + dog.i + ", j = " + dog.j);
FileOutputStream fos = new FileOutputStream("abc.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(dog);
FileInputStream fis = new FileInputStream("abc.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
Dog dog2 = (Dog) ois.readObject();
System.out.println("after deserialization: i = " + dog2.i + ", j = " + dog2.j);
}
public static class Dog implements Serializable {
int i = 10;
int j = 20;
private void writeObject(ObjectOutputStream oos) throws IOException{
//oos.defaultWriteObject();
System.out.println("In WriteObject");
oos.writeInt(i);
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
//ois.defaultReadObject();
System.out.println("In ReadObject");
i = ois.readInt();
}
}
}
Выход для этого кода:
before serialization: i = 10, j = 20
In WriteObject
In ReadObject
after deserialization: i = 10, j = 0
Как видите, oos.defaultWriteObject()
а также ois.defaultReadObject();
комментируются, и мы сохраняем и восстанавливаем только переменную экземпляра i
,
Итак, верно ли мое предположение, что мы можем смоделировать концепцию экстернализации с помощью пользовательской сериализации?
1 ответ
Итак, верно ли мое предположение, что мы можем смоделировать концепцию экстернализации с помощью пользовательской сериализации?
Ваше предположение верно, что программист имеет возможность создать любую сериализованную форму для своего класса, которую он выберет.
Serializable
interface - интерфейс маркера, который сигнализирует среде выполнения Java, что сериализация на основе Java включена для реализующего класса. Если вы больше ничего не делаете, Java Runtime вызывает средство сериализации по умолчанию, которое создает сериализованную форму для вас из всех полей экземпляра вашего класса.
Лучшей сериализованной формой для класса является та, которая:
- Описывает только логическое состояние своих экземпляров
- Не содержит специфических для реализации деталей или метаданных
- Записывает и считывает минимальную информацию, необходимую для потоковой передачи и восстановления экземпляров классов.
Например, в вашем коде выше, если оба i
а также j
опишите значимое состояние ваших объектов, затем сериализованную форму, которая не включала j
будет иметь недостатки, так как вы не сможете восстановить объект в его значимое состояние после десериализации.
Однако если i
описывает значимое состояние, но j
это деталь реализации, которая не является частью логического состояния объекта, тогда было бы лучше исключить j
из потока, чтобы получить более оптимальную сериализованную форму.
Хотя сериализованная форма по умолчанию (испускаемая встроенным средством сериализации Java) часто подходит для простых классов значений, более сложные абстракции содержат метаданные и информацию о реализации, которые не должны становиться частью их сериализованных форм.
Чтобы помочь программистам разработать лучшую сериализованную форму для своих классов (если форма по умолчанию не подходит), Java предоставляет два широких механизма для генерации оптимальной сериализованной формы для объектов:
- Индивидуальная сериализация
Externalizable
интерфейс
Первая стратегия позволяет программисту изменять поведение встроенного средства сериализации Java, используя transient
ключевое слово, и подключается к таким методам, как readObject()
, writeObject()
, readResolve()
и т. д. Использование прокси-серверов сериализации особенно рекомендуется для классов с неизменяемыми значениями с инвариантами, которые должны быть защищены.
Последняя стратегия должна быть реализована программистом Externalizable
вместо Serializable
(Externalizable
сам расширяется Serializable
). Externalizable
интерфейс, в отличие от Serializable
не является маркером интерфейса. Его методы, когда они реализованы, предназначены для того, чтобы дать программисту полный контроль над тем, как сериализованная форма объекта испускается и восстанавливается.
"Основное преимущество экстернализации по сравнению с сериализацией состоит в том, что экстернализация сохраняет только часть объекта, а не весь объект, как в случае сериализации".
Сериализованная форма, которая содержит только "часть объекта" и которая не содержит всей информации, необходимой для восстановления состояния объекта, существовавшего до его сериализации, является ошибочной сериализованной формой. Можно ожидать, что такая форма вызовет проблемы на тех платформах, которые полагаются на сериализацию для межпроцессного взаимодействия.