SerialVersionUID
SerialVersionUID — идентификатор класса в языке Java, используемый при сериализации с использованием стадартного алгоритма. Хранится как числовое значение типа long.
Назначение идентификатора[править]
В каждый класс, реализующий интерфейс Serializable, на стадии компиляции добавляется еще одно поле — static final long serialVersionUID. Это поле содержит уникальный идентификатор версии сериализованного класса. Оно вычисляется по содержимому класса — полям, их порядку объявления, методам, их порядку объявления. Соответственно, при любом изменении в классе это поле поменяет свое значение. Это поле записывается в поток при сериализации класса. При десериализации значение этого поля сравнивается со значением такого же поля у класса, загруженного в виртуальную машину. Если значения не совпадают — инициируется исключение java.io.InvalidClassException, в противном случае выполняется десериализация объекта.
При изменении деталей методов класса прочитать старые данные может оказаться невозможно, поскольку даже незначительные изменения в классе могут повлечь изменение serialVersionUID. Чтобы избежать этого, можно вручную в классе определить поле private static final long serialVersionUID. Этот приём позволит проводить десериализацию объектов старых версий классов.
Совместимые и несовместимые изменения[править]
Выделяют два типа изменений класса — совместимые и несовместимые. Несовместимые изменения — это такие изменения, при которых работа со старой версией класса может привести к ошибке. Несовместимые изменения могут возникнуть в следующих случаях:
- Удаление полей. При десериализации поля объекта, для которых не найдено значение в потоке байт, оно инициализируется значением по умолчанию. Однако, это значение может нарушать контракт класса более ранней версии. Аналогичная проблема при превращении нестатических полей в статические, а также добавлении к полям модификатора transient.
- Изменение порядка следования классов в иерархии наследования, так как это нарушает последовательность данных в потоке.
- Изменение типа примитивного поля, что повлечёт невозможно считать эти данные из потока.
- Изменение методов writeObject или readObject, а также замена интерфейса Serializable на Externalizable или наоборот. В этом случае может быть нарушена логика сериализации-десериализации.
- Замена объекта ссылочного типа с обычного на перечисление или наоборот.
- Удаление интерфейса Serializable или Externalizable.
- Добавление методов writeReplace или readResolve несовместимо в том случае, когда их поведение порождает объект не совместимый с более старой версией класса.
Совместимые изменения:
- Добавление полей в класс. Поля, отсутствующие в потоке байт, будут проинициализированы по умолчанию. Чтобы поле инициализировалось другим значением, в класс можно добавить метод readObject. Аналогично совместимыми изменениями являются модификация статических полей в нестатические, а также удаление модификатора transient.
- Добавление класса в иерархию или его удаление.
- Добавление или удаление методов writeObject/readObject.
- Добавление интерфейса java.io.Serializable. Эквивалентно добавлению типов. В потоке отсутствуют данные для этого класса, так что его поля проинициализируются значениями по умолчанию.
- Изменение уровня видимости поля, поскольку модификаторы доступа не влияют на способность объекта сериализироватся.
Факты[править]
- serialVersionUID является единственным статическим членом класса, который записывается в поток при сериализации объекта.
Ссылки[править]
- Serializable // Oracle
- Versioning of Serializable Objects // Oracle