Сериализация объектов в 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 Также в библиотеке
Kysely для TypeScript: полное руководство с примерами
Генерация PDF отчётов на JavaScript (Node.js): Puppeteer, PDFKit, jsPDF
InversifyJS: IoC-контейнер для TypeScript-приложений
Машинное обучение на PHP: обзор библиотек для ML
Планировщик задач Kotlin: kotlinx.coroutines и библиотеки для фоновых задач