Ответ
Serializable — это интерфейс-маркер (не содержит методов) в пакете java.io. Его реализация указывает, что объекты класса могут быть сериализованы — преобразованы в последовательность байтов для сохранения в файл, передачи по сети или сохранения в памяти. Обратный процесс называется десериализацией.
Базовый пример:
import java.io.*;
// Класс должен реализовать интерфейс-маркер Serializable
class Person implements Serializable {
// serialVersionUID для контроля версий класса
private static final long serialVersionUID = 1L;
private String name; // Будет сериализовано
private transient int age; // Поле помечено transient - НЕ будет сериализовано
private Address address; // Должен также быть Serializable, иначе исключение
// Конструкторы, геттеры, сеттеры...
}
class Address implements Serializable { // Вложенный объект тоже должен быть сериализуем
private String city;
}
public class SerializationExample {
public static void main(String[] args) {
Person person = new Person("Alice", 30, new Address("Moscow"));
// СЕРИАЛИЗАЦИЯ (объект -> байты)
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.dat"))) {
oos.writeObject(person);
} catch (IOException e) { e.printStackTrace(); }
// ДЕСЕРИАЛИЗАЦИЯ (байты -> объект)
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.dat"))) {
Person deserializedPerson = (Person) ois.readObject();
System.out.println(deserializedPerson.getName()); // "Alice"
System.out.println(deserializedPerson.getAge()); // 0 (значение по умолчанию, т.к. transient)
} catch (IOException | ClassNotFoundException e) { e.printStackTrace(); }
}
}
Ключевые аспекты и best practices:
-
serialVersionUID:- Уникальный идентификатор версии сериализованного класса.
- Всегда объявляйте его явно (
private static final long). Если его нет, JVM сгенерирует его автоматически на основе структуры класса. Любое изменение класса (добавление поля) приведет к изменению сгенерированного UID и вызоветInvalidClassExceptionпри десериализации старого объекта.
-
Модификатор
transient:- Поля, помеченные
transient, игнорируются при сериализации. При десериализации они получают значения по умолчанию (null,0,false). - Используется для полей, которые не имеют смысла сохранять (например, кэши, дескрипторы файлов,
Thread) или являются производными.
- Поля, помеченные
-
Вложенные объекты: Все не-
transientполя класса должны быть сериализуемыми, иначе будет выброшеноNotSerializableException. -
Безопасность и производительность:
- Нативная сериализация Java может быть медленной и создавать большие бинарные данные. Для высокопроизводительных сценариев рассмотрите альтернативы (JSON, Protobuf, Avro).
- Не десериализуйте данные из ненадежных источников — это классический вектор атак (десериализация может привести к выполнению произвольного кода).
-
Кастомная логика: Можно определить методы
private void writeObject(ObjectOutputStream out)иprivate void readObject(ObjectInputStream in)для полного контроля над процессом сериализации.