История вопроса
С начала существования Java появилась задача сохранять объекты между сессиями работы приложений — передавать по сети, записывать в базу данных или на диск. Для этого был придуман интерфейс Serializable, который позволил превращать объекты в поток байтов и обратно (сериализация и десериализация).
Проблема
Если класс не реализует интерфейс Serializable, попытка сериализовать его экземпляр выбросит исключение. Более того, сериализация сохраняет не только значения полей, но и их состояние, так что неверная реализация может привести к неожиданной уязвимости, ошибкам восстановления объекта или даже потере данных.
Решение
Интерфейс Serializable маркерный, то есть не содержит методов. Для корректной сериализации стоит явно указывать serialVersionUID, а также использовать ключевое слово transient для полей, которые не должны сериализоваться.
Пример кода:
import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = 1L; private String username; private transient String password; // не будет сериализовано public User(String username, String password) { this.username = username; this.password = password; } }
Ключевые особенности:
Обязательно ли явно объявлять поле serialVersionUID?
Нет, не обязательно, но если не объявить, оно будет сгенерировано автоматически. Однако при изменениях класса восстановление старой сериализованной версии может привести к InvalidClassException. Поэтому лучше всегда явно объявлять это поле.
Сериализуются ли статические поля?
Нет, сериализуются только нестатические (instance) поля. Статические поля принадлежат классу, а не объекту, и поэтому их значения при сериализации и десериализации не сохраняются и не восстанавливаются.
Можно ли сериализовать объект, поля которого не реализуют Serializable?
Нет, если хотя бы одно нестатическое поле не сериализуемо и не объявлено как transient, попытка сериализации вызовет исключение NotSerializableException.
В приложении для кэширования пользователей не указывали serialVersionUID, а при доработке кода изменили структуру класса User. При старте приложения возник InvalidClassException и потерялись все сериализованные данные.
Плюсы:
Минусы:
В схожем проекте всегда явно указывали serialVersionUID и все поля, не подлежащие сериализации, делали transient. Благодаря этому сериализованные объекты успешно загружались после изменения незначительной структуры класса.
Плюсы:
Минусы: