Serialversionuid java что это
Перейти к содержимому

Serialversionuid java что это

  • автор:

Зачем использовать SerialVersionUID внутри Serializable класса в Java

Java-университет

Зачем использовать SerialVersionUID внутри Serializable класса в Java - 1

Serialization и SerialVersionUID всегда остается загадкой для многих Java-разработчиков. Я часто вижу вопросы насчет того что такое SerialVersionUID , или что произойдет, если я не объявлю SerialVersionUID в моем Serializable -классе? Помимо запутанного и редкого использования, есть еще одна причина для этого вопроса — это предупреждение Eclipse IDE об отсутствии SerialVersionUID , например: «The Serializable class Customer does not declare a static final SerialVersionUID field of type long» (» Serializable -класс Customer не объявил статическое финальное поле SerialVersionUID типа long»). В этой статье, вы сможете не только узнать основы Java SerialVersionUID но и его влияние на процесс сериализации и де-сериализации. Когда вы объявляете класс, как Serializable путем реализации интерфейса-маркера java.io.Serializable , среда выполнения Java сохраняет экземпляр этого класса на диске с помощью механизма сериализации по умолчанию, если вы не настроили процесс использования интерфейса Externalizable. Во время сериализации, среда выполнения Java создает номер версии для класса, так что она может десереализировать его позже. В Java этот номер версии известен как SerialVersionUID . Если во время десериализации, SerialVersionUID не соответствует, то процесс завершится с исключением InvalidClassException в потоке » main » java.io.InvalidClassException , а также напечатает имя класса и соответствующий SerialVersionUID . Быстрое решение для исправления этой проблемы – скопировать SerialVersionUID и определить его как константу типа private static final long в вашем классе. В этой статье мы узнаем, о том, почему мы должны использовать SerialVersionUID в Java и как использовать инструмент serialver JDK для генерации этого ID. Если вы новичок в сериализации, вы также можете посмотреть Топ 10 вопросов о сериализации Java на интервью чтобы оценить свои знания и найти пробелы в вашем понимании для дальнейшего чтения. Подобно Concurrency (параллельности) и Multi-threading (многопоточности), Serialization (сериализация) это уже другая тема, которая заслуживает чтения несколько раз.

Зачем использовать SerialVersionUID в Java

Как я сказал, когда мы не определилили значение SerialVersionUID как static final long в нашем классе, механизм сериализации сделает это за нас. Этот механизм чувствителен ко многим деталям, включая поля вашего класса, их модификаторы доступа, интерфейсы, которые он реализует и даже различные реализации компилятора, любые изменения в классе или использование другого компилятора может дать результат иного SerialVersionUID , который в конечном итоге остановит перезагрузку сериализованных данных.Очень рискованно полагаться на механизм сериализации Java для генерации этого id, вот почему рекомендуется явно определять SerialVersionUID в вашем Serializable-классе. Я настоятельно советую прочитать классику Java — Joshua Bloch “Effective Java” для понимания сериализации Java и проблем неправильной их обработки. Кстати, JDK также предоставляет инструмент serialver , который расположен в директории bin каталога JAVA_HOME, на моем компьютере C:\Program Files\Java\jdk1.6.0_26\bin\serialver.exe, который может быть использован для генерирования SerialVersionUID для старых классов. Это очень полезно в случае, если вы внесли изменения в ваш класс, который нарушает сериализацию и ваше приложение не может перезагрузить сериализированные экземпляры. Вы легко можете использовать эту утилиту для создания SerialVersionUID для старых экземпляров, а затем использовать его в явном виде объявив поле как private static final long SerialVersionUID . Кстати, очень рекомендуется из соображений производительности и безопасности использовать обычный двоичный формат для сериализации, опять же “Effective Java” имеет несколько параграфов, которые демонстрируют преимущества обычного формата в мельчайших деталях.

Как использовать утилиту serialver JDK для генерирования SerialVersionUID

Вы можете использовать serialver для генерирования SerialVersionUID для классов. Это особенно полезно для развивающихся классов, утилита возвращает SerialVersionUID в формате легком для копирования. Вы можете использовать утилиту serialver JDK как показано в примере:

 $ serialver use: serialver [-classpath classpath] [-show] [classname. ] $ serialver -classpath . Hello Class Hello is not Serializable. $ serialver -classpath . Hello Hello: static final long SerialVersionUID = -4862926644813433707L; 

Вы также можете использовать утилиту serialver в GUI виде используя команду $ serialver –show , это откроет инспектор serial version , который принимает полное имя класса и показывает его Serial version .

Резюме

Зачем использовать SerialVersionUID внутри Serializable класса в Java - 2

Теперь мы знаем что такое SerialVersionUID и почему важно объявлять его в Serializable -классе, самое время пересмотреть некоторые важные факты связанные с Java SerialVersionUID.

  1. SerialVersionUID используется для указании версии сериализованных данных.
  2. Когда мы не объявляем SerialVersionUID в нашем классе, среда выполнения Java делает это за нас, но этот процесс чувствителен ко многим метаданным класса включая количество полей, тип полей, модификаторы доступа полей, интерфейсов, которые реализованы в классе и пр. Вы можете найти точную информацию в документации о сериализации от Oracle.
  3. Рекомендуется объявлять SerialVersionUID как private static final long переменную во избежание механизма по умолчанию. Некоторые IDE, такие как Eclipse, также выдают предупреждения если вы забыли это, например: «The Serializable class Customer does not declare a static final SerialVersionUID field of type long» («Serializable-класс Customer не объявил статическое финальное поле SerialVersionUID типа long»). Хотя вы и можете отключить это предупреждение следуя в Window > Preferences > Java > Compiler > Errors / Warnings > Potential Programming Problems, я предлагаю не делать этого. Только когда восстановление данных не требуется я могу быть небрежным в этом. Вот как эта ошибка выглядит в Eclipse IDE, все что вам нужно это принять первое быстрое решение.
  4. Вы также можете использовать утилиту serialver из JDK для генерирования Serial Version для классов в Java. Утилита также имеет GUI, который включается при передаче параметра – show .
  5. Лучшая практика в сериализации – это явно объявить SerialVersionUID , чтобы избежать любых проблем при де-сериализации, особенно если вы работаете с клиент-серверным приложением, которое опирается на сериализованные данные, например, RMI.

Это все про SerialVersionUID в Java. Сейчас мы знаем почему важно правильно объявлять SerialVersionUID в классе. Вы можете сказать спасибо вашей IDE за это напоминание, которое потенциально может нарушить де-сериализацию вашего класса. Если вы хотите больше прочитать про сериализацию и родственные понятия, вы можете также посмотреть эти удивительные статьи.

  • Difference between transient and volatile variable in Java
  • Difference between Serializable and Externalizable interface in Java
  • When to use transient variable in Java

Оригинал здесь

Зачем нужен serialVersionUID в Java и как его использовать

При работе со средой разработки Eclipse, разработчики могут столкнуться с таким предупреждением: «The serializable class Foo does not declare a static final serialVersionUID field of type long». Это сообщение говорит о том, что в сериализуемом классе отсутствует поле serialVersionUID.

Что такое serialVersionUID?

В Java, serialVersionUID — это поле, используемое в сериализуемых классах. Это уникальный идентификатор для каждого класса, который используется в процессе десериализации для проверки того, что загруженный класс и оригинальный класс в точности совпадают.

Зачем он нужен?

Без этого поля процесс десериализации может привести к InvalidClassException , если версия класса изменилась между сериализацией и десериализацией. Это может произойти, если были внесены изменения в класс, например, добавлены или удалены поля.

Пример проблемы

Рассмотрим следующий пример:

import java.io.*; class Foo implements Serializable < int x; int y; >public class Main < public static void main(String[] args) < Foo foo = new Foo(); foo.x = 3; foo.y = 4; // Сериализация foo try < ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("foo.ser")); out.writeObject(foo); out.close(); >catch (IOException e) < e.printStackTrace(); >// Изменение класса Foo // . // Десериализация foo try < ObjectInputStream in = new ObjectInputStream(new FileInputStream("foo.ser")); Foo fooRead = (Foo) in.readObject(); in.close(); >catch (IOException | ClassNotFoundException e) < e.printStackTrace(); >> >

Если класс Foo был изменен после сериализации (например, было добавлено новое поле), процесс десериализации может вызвать исключение InvalidClassException .

Как использовать serialVersionUID?

Чтобы избежать этого исключения, можно явно объявить поле serialVersionUID в классе:

class Foo implements Serializable

Это гарантирует, что любые изменения в классе не повлияют на процесс десериализации, если они не изменяют семантику объекта.

Таким образом, serialVersionUID является важным инструментом в обеспечении стабильности и совместимости сериализуемых классов в Java.

Есть ли разница между своим значением поля serialVersionUID и тем, который генерирует jdk?

Среда разработки всегда предлагает гигантские значения поля serialVersionUID . Но в интернете я прочитал, что полю можно дать любое значение, например 1:

private static final long serialVersionUID = 1L; 

Есть ли разница между своим значением serialVersionUID и тем, который генерирует IDE ? И если разницы нет, то зачем такие громадные значения? P.S. Я знаю, 1 и громадные значения занимают одинаковое место в памяти. Меня интересует лишь, в чём смысл громадных значений, если всегда можно написать 1. В jdk есть даже специальная утилита для генерации serialVersionUID !

Отслеживать
задан 28 янв 2023 в 11:56
2,326 2 2 золотых знака 11 11 серебряных знаков 38 38 бронзовых знаков

Разницы никакой, смысл в самом существовании этого поля. А вот «гигантские» значения, генерируемые IDE, и написанное Вами 1L занимают в памяти абсолютно одинаково места. Почитайте про типы.

30 янв 2023 в 10:28

@Adm123 Про то, что 1L и 1234567890L занимают одинаковое место, я знаю, но все эти огромные значения усложняют код в плане читаемости. Вот я и спрашиваю, зачем же они нужны?

31 янв 2023 в 4:01

Генератор — генерирует ) Согласитесь, было бы странно, если бы генератор long-значений отдавал только числа в пределах от 0 до 9. Только в этом и «смысл».

31 янв 2023 в 8:02
@Adm123 если можно было бы использовать значения от 1 до 9, то генератора бы не было =).
2 фев 2023 в 13:17

2 ответа 2

Сортировка: Сброс на вариант по умолчанию

Генератор высчитывает serialVersionUID на основе содержимого класса (по сути хеш-сумму из сигнатур класса и полей, всего что участвует в сериализации) — это гарантирует (в высокой степени вероятности) уникальный serialVersionUID для уникальной структуры класса.
Если вы ставите своё число, то должны осознавать какие изменения класса критичны для (де)сериализации и менять serialVersionUID после таких изменений.

Отслеживать
ответ дан 3 фев 2023 в 18:49
12.1k 1 1 золотой знак 15 15 серебряных знаков 32 32 бронзовых знака

Да, есть разница. serialVersionUID является уникальным идентификатором, который используется для верификации сериализованного класса. Если вы задаете свое значение для serialVersionUID , то это значение должно соответствовать текущей версии класса. Если вы используете значение, генерируемое JDK, то оно автоматически обновляется при изменении класса. В этом случае рекомендуется использовать значение, генерируемое JDK, чтобы избежать несовместимости между сериализованным классом и десериализованным классом.

Нет разницы между своим значением serialVersionUID и тем, который генерирует JDK или IDE, но указание своего значения может дать вам больше контроля над версией класса.

Уже ответили, что в Java serialVersionUID — это уникальный идентификатор класса, который используется при сериализации и десериализации. Если хотите управлять версией класса, укажете свое значение serialVersionUID.

serialVersionUID значение, сгенерированное JDK/IDE, является длинным целым числом, что обеспечивает уникальность для каждого класса. Такое большое значение необходимо, чтобы избежать коллизий, когда вы работаете с множеством классов.

В ответ на статью «Зачем использовать SerialVersionUID внутри Serializable класса в Java»

Java-университет

В ответ на статью

Итак.. Имеем класс, который хотим сериализовать обычными методами (используем Serializable )

 package Serialization; import java.io.Serializable; public class SerializableClass implements Serializable

Пишем тестовое приложение. Сразу оговорюсь, что моя цель показать, что нам дает serialVersionUID .

 package Serialization; import java.io.*; public class MainSerializable < final static String FILE_NAME = "c:\\File.dat"; public static void serialize(Object object) throws IOException < FileOutputStream fileOutputStream = new FileOutputStream(FILE_NAME); ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(object); fileOutputStream.close(); objectOutputStream.close(); >public static Object deserialize() throws IOException, ClassNotFoundException < FileInputStream fileInputStream = new FileInputStream(FILE_NAME); ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream); Object object = objectInputStream.readObject(); objectInputStream.close(); return object; >public static void main(String[] args) throws IOException, ClassNotFoundException < SerializableClass serializableClass = new SerializableClass(); serialize(serializableClass); SerializableClass newObject = (SerializableClass) deserialize(); >> 

Все прекрасно работает. Класс сериализуется в файл FILE_NAME = «c:\\File.dat» . Смеркалось. 🙂 Забыли в класс добавить поля. Добавляем:

 public class SerializableClass implements Serializable < private String name; private int number; private String FirstName; // + private String LastName; // + >

Вроде все хорошо.. все компилится.. Итак запускаем main , десериализуем класс SerializableClass из файла » c:\\File.dat «:

 public static void main(String[] args) throws IOException, ClassNotFoundException

Ой. Что-делать.

 Exception in thread "main" java.io.InvalidClassException: Serialization.SerializableClass; local class incompatible: stream classdesc serialVersionUID = 8129437039424566964, local class serialVersionUID = -8271479231760195917 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) at Serialization.MainSerializable.deserialize(MainSerializable.java:22) at Serialization.MainSerializable.main(MainSerializable.java:30) 

В общем все честно. Класс изменился и его serialVersionUID = -8271479231760195917 , а сериализованного в файле serialVersionUID = 8129437039424566964 . Что теперь делать, как быть? Как создать экземпляр? Выход есть. Нужно в нашем классе объявить: static final long serialVersionUID , которая равна serialVersionUID засеренного 🙂 класса в файле. Т.е. мы сказали, что давай, десериализируся.. ты можешь.. версии то у тебя одинаковые:

 package Serialization; import java.io.Serializable; public class SerializableClass implements Serializable < static final long serialVersionUID = 8129437039424566964L; private String name; private int number; private String FirstName; // + private String LastName; // + >

Запускаем. И.. Все работает Как я понял, можно было этой ошибки избежать, если в классе заранее объявить:

 public class SerializableClass implements Serializable

Т.е. мы не даем Java самой высчитывать serialVersionUID на основании своих алгоритмов (довольно сложных алгоритмов). Теперь при любом изменении класса у нас serialVersionUID = 1L Проверяем:

 public static void main(String[] args) throws IOException, ClassNotFoundException

Работает.. А теперь так:

 public class SerializableClass implements Serializable < static final long serialVersionUID = 1L; //private String name; //private int number; >

Есть.. А так?

 public class SerializableClass implements Serializable < static final long serialVersionUID = 1L; public int A; protected String value; //private String name; //private int number; >

Круто.. все продолжает работать. Вот и закончил свою первую статью. Я все это хотел вложить в комменты, но не пролез по символам. Приму трезвую критику и замечания P.S. Спасибо автору, который сподвиг меня на эти изыски.. Наверное, так и учатся 🙂 Всем успехов 🙂

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *