Сериализация объектов в Java: полное руководство для начинающих

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Сериализация объектов в Java: что это и зачем нужно?

Сериализация в Java — это процесс преобразования состояния объекта в поток байтов для сохранения в файл, базу данных или передачи по сети. Обратный процесс — восстановление объекта из байтового потока — называется десериализацией. Эта технология лежит в основе многих Java-фреймворков: от RMI (Remote Method Invocation) до систем обмена сообщениями.

В этой статье мы разберем, как работает встроенная сериализация Java, на практических примерах, и рассмотрим лучшие практики её использования.

Как работает сериализация в Java?

Java предоставляет встроенный механизм сериализации через интерфейс java.io.Serializable. Этот интерфейс не содержит методов — он является маркерным (marker interface). Если класс реализует Serializable, JVM автоматически разрешает сериализацию его объектов.

Для записи и чтения объектов используются два основных класса из пакета java.io:

  • ObjectOutputStream — сериализует объект в поток байтов
  • ObjectInputStream — десериализует объект из потока байтов

Простой пример сериализации

Создадим класс Person, который можно будет сериализовать:

import java.io.Serializable;

public class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;
    private transient String password; // не будет сериализовано

    public Person(String name, int age, String password) {
        this.name = name;
        this.age = age;
        this.password = password;
    }

    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + ", password='" + password + "'}";
    }
}

Теперь напишем код для сериализации и десериализации:

import java.io.*;

public class SerializationDemo {
    public static void main(String[] args) {
        Person person = new Person("Иван", 30, "secret123");
        
        // Сериализация
        try (FileOutputStream fos = new FileOutputStream("person.ser");
             ObjectOutputStream oos = new ObjectOutputStream(fos)) {
            oos.writeObject(person);
            System.out.println("Объект сериализован: " + person);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // Десериализация
        try (FileInputStream fis = new FileInputStream("person.ser");
             ObjectInputStream ois = new ObjectInputStream(fis)) {
            Person restoredPerson = (Person) ois.readObject();
            System.out.println("Объект восстановлен: " + restoredPerson);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

Вывод программы:

Объект сериализован: Person{name='Иван', age=30, password='secret123'}
Объект восстановлен: Person{name='Иван', age=30, password='null'}

Обратите внимание: поле password было помечено ключевым словом transient и при десериализации получило значение null. Это стандартный способ исключения конфиденциальных данных из сериализации.

Важные особенности сериализации в Java

  • serialVersionUID — уникальный идентификатор версии класса. Если не объявить его явно, JVM сгенерирует его автоматически, но это может привести к ошибке InvalidClassException при изменении класса. Рекомендуется всегда объявлять private static final long serialVersionUID.
  • Статические поля не сериализуются — они принадлежат классу, а не объекту.
  • Вложенные объекты — если сериализуемый объект содержит ссылки на другие объекты, они тоже должны быть сериализуемы (реализовывать Serializable), иначе возникнет NotSerializableException.
  • Наследование — если родительский класс реализует Serializable, то все его наследники автоматически становятся сериализуемыми.

Кастомная сериализация с writeObject и readObject

Иногда требуется тонкий контроль над процессом сериализации. Для этого можно реализовать приватные методы writeObject() и readObject() в самом классе:

import java.io.*;

public class User implements Serializable {
    private static final long serialVersionUID = 2L;
    private String username;
    private transient String password;

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    private void writeObject(ObjectOutputStream oos) throws IOException {
        oos.defaultWriteObject();
        // Шифруем пароль перед записью
        String encryptedPassword = encrypt(password);
        oos.writeObject(encryptedPassword);
    }

    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
        ois.defaultReadObject();
        // Дешифруем пароль после чтения
        String encryptedPassword = (String                    

Рекомендаций