Gymterview
junior

Опишите процесс сериализации/десериализации с использованием Serializable

При использовании Serializable JVM применяет алгоритм сериализации, который через Reflection API автоматически записывает состояние объекта в поток байтов.

Алгоритм сериализации

  1. Запись метаданных о классе — имя класса, serialVersionUID, идентификаторы полей
  2. Рекурсивная запись описания суперклассов вплоть до java.lang.Object (не включительно)
  3. Запись примитивных значений полей, начиная с полей самого верхнего суперкласса
  4. Рекурсивная запись объектов, являющихся полями сериализуемого объекта

Ранее сериализованные объекты повторно не записываются — это позволяет корректно обрабатывать циклические ссылки и граф объектов.

Алгоритм десериализации

  1. Под объект выделяется память
  2. Поля заполняются значениями из потока
  3. Конструктор сериализуемого класса не вызывается
  4. Вызывается конструктор без параметров ближайшего несериализуемого родительского класса

Если у несериализуемого суперкласса нет конструктора без параметров, при десериализации будет выброшено InvalidClassException.

Пример сериализации/десериализации
import java.io.*;

public class SerializationExample {
    public static void main(String[] args) throws Exception {
        User user = new User("Иван", 30);

        // Сериализация
        try (ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream("user.ser"))) {
            oos.writeObject(user);
        }

        // Десериализация
        try (ObjectInputStream ois = new ObjectInputStream(
                new FileInputStream("user.ser"))) {
            User restored = (User) ois.readObject();
            System.out.println(restored); // User{name='Иван', age=30}
        }
    }
}

class User implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
    // getters, toString...
}

Частые ошибки

  • Ожидание вызова конструктора при десериализации — конструктор сериализуемого класса не вызывается, поэтому логика инициализации в нём не выполнится
  • Отсутствие Serializable у вложенных объектов — если поле класса не реализует Serializable и не помечено transient, будет NotSerializableException
  • Забыть про суперкласс — если родитель не Serializable, его поля не сохраняются, а при десериализации инициализируются через конструктор по умолчанию

На собеседовании: ключевой момент — конструктор не вызывается при десериализации Serializable-объекта, но вызывается конструктор без параметров у несериализуемого суперкласса. Это частый вопрос-ловушка.