В Java serialVersionUID
– это что-то вроде контроля версий, гарантирующего, что как сериализованные, так и десериализованные объекты используют совместимый класс.
Например, если объект сохранен в файл (сериализация) с serialVersionUID=1L
, , когда мы преобразуем файл обратно в объект (сериализация), мы должны использовать тот же
serialVersionUID=1L , в противном случае
создается исключение InvalidClassException
Exception in thread "main" java.io.InvalidClassException: com.mkyong.io.object.Address; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2
1. ПОЖО
Просмотрите простой Адрес
класс, реализует Сериализуемый
и объявляет serialVersionUID
.
package com.mkyong.io.object; import java.io.Serializable; public class Address implements Serializable { private static final long serialVersionUID = 1L; String street; String country; public Address(String street, String country) { this.street = street; this.country = country; } public String getStreet() { return street; } public void setStreet(String street) { this.street = street; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } @Override public String toString() { return "Address{" + "street='" + street + '\'' + ", country='" + country + '\'' + '}'; } }
2. Проверьте serialVersionUID.
2.1 Сохраните объект в файл и преобразуйте его обратно из файла в объект.
package com.mkyong.io.object; import java.io.*; public class ObjectUtils { public static void main(String[] args) throws IOException, ClassNotFoundException { Address address = new Address("abc", "Malaysia"); // object -> file try (FileOutputStream fos = new FileOutputStream("address.obj"); ObjectOutputStream oos = new ObjectOutputStream(fos)) { oos.writeObject(address); oos.flush(); } Address result = null; // file -> object try (FileInputStream fis = new FileInputStream("address.obj"); ObjectInputStream ois = new ObjectInputStream(fis)) { result = (Address) ois.readObject(); } System.out.println(result); } }
Выход
Address{street='abc', country='Malaysia'}
2.2 Обновите serialVersionUID
до 99L
.
public class Address implements Serializable { private static final long serialVersionUID = 99L; String street; String country; //...
Повторите процесс десериализации.
Address result = null; // file -> object try (FileInputStream fis = new FileInputStream("address.obj"); ObjectInputStream ois = new ObjectInputStream(fis)) { result = (Address) ois.readObject(); } System.out.println(result);
Теперь мы попали Исключение InvalidClassException
.
Exception in thread "main" java.io.InvalidClassException: com.mkyong.io.object.Address; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 99 at java.base/java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:689) at java.base/java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1903) at java.base/java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1772) at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2060) at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1594) at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:430)
3. Когда я должен обновить идентификатор serialVersionUID?
Когда мы изменяем класс, который нарушит совместимость с существующим сериализованным объектом, например, мы обновляем текущий Адрес
класс, с добавлением и удалением некоторых полей.
Это новое изменение приведет к сбою всех существующих сериализованных объектов, затем мы должны обновить serialVersionUID
.
public class Address implements Serializable { private static final long serialVersionUID = 9999L; String line1; String line2; Country country; //String street; //String country; }
4. Идентификатор серийной версии по умолчанию?
Если serialVersionUID
не объявлен, JVM будет использовать свой алгоритм для создания serialVersionUID по умолчанию
, проверьте алгоритм здесь . Вычисление по умолчанию serialVersionUID
очень чувствительно к деталям класса и может отличаться в разных реализациях JVM и приводить к неожиданному Исключения InvalidClassExceptions
во время процесса десериализации.
Рассмотрим следующий пример:
Среда Клиент/сервер – Клиент использует OpenJDK в Windows. – Сервер использует GraalVM В Linux.
Клиент отправляет сериализованный класс с serialVersionUID=1L
на сервер. Сервер может десериализовать класс с другим serialVersionUID=99L
и выбрасывает Исключение Invalidclassexception
. Поскольку оба используют разные реализации JVM, на обоих сайтах может быть создан другой serialVersionUID
.
Существует множество реализаций JVM
Скачать Исходный Код
$клон git https://github.com/mkyong/core-java.git
$cd java-ввод-вывод
Рекомендации
- Википедия – Сериализация
- Википедия – Реализация JVM
- Сериализуемый JavaDoc
- StackOverflow – явный serialVersionUID считается вредным?
- Java – Как сгенерировать serialVersionUID
- Примеры сериализации Java
- Java – Что такое переходные поля?
Оригинал: “https://mkyong.com/java-best-practices/understand-the-serialversionuid/”