Сериализация
Объект как последовательность байтов
Встроенная сериализация Java умеет записать состояние объекта в поток байтов,
а затем восстановить объект из такого потока. Для стандартного механизма класс обычно помечают
маркерным интерфейсом Serializable — у него нет методов, он лишь сообщает механизму сериализации о допустимости операции.
class User implements Serializable {
String name;
int age;
}
Запись выполняется через ObjectOutputStream,
а чтение — через ObjectInputStream.
Сериализуется не только сам объект, но и достижимый из него граф объектов, если соответствующие значения тоже поддерживают сериализацию.
Запись и чтение
try (ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("user.bin"))) {
out.writeObject(user);
}
try (ObjectInputStream in = new ObjectInputStream(
new FileInputStream("user.bin"))) {
User restored = (User) in.readObject();
}
Десериализация создаёт новый объект на основе данных потока.
При этом обычные конструкторы сериализуемого класса не являются тем же механизмом восстановления состояния,
поэтому сериализацию нельзя воспринимать как простое повторное выполнение new.
serialVersionUID и transient
Поле serialVersionUID задаёт версию сериализованной формы класса.
Если совместимость формы нарушена, чтение старых данных может завершиться InvalidClassException.
Явное значение делает намерение разработчика понятнее.
class Session implements Serializable {
private static final long serialVersionUID = 1L;
String user;
transient String token;
}
Поле transient не сохраняется стандартным механизмом сериализации.
Статические поля также не являются состоянием конкретного объекта и не записываются как его экземплярные данные.
ObjectInputStream для недоверенного входа опасен: обработка специально подготовленного потока может привести к серьёзным последствиям.
Если встроенная сериализация всё же используется на границе доверия, нужны фильтры десериализации и строгие ограничения допустимых классов и размеров.
Для новых внешних протоколов и долговременного хранения обычно выбирают явные форматы данных, где схема и правила совместимости контролируются отдельно. Встроенная сериализация чаще встречается в существующем Java-коде или в задачах, где обе стороны полностью контролируются одним приложением.