Что такое serialVersionUID?
Быстрый и практический пример использования serialVersionUID в Java.
1. Обзор
В этом кратком руководстве мы обсудим, что такое serialVersionUID и как его использовать на примерах.
2. UID серийной версии
Проще говоря, мы используем serialVersionUID атрибут для запоминания версий Сериализуемый класс для проверки совместимости загруженного класса и сериализованного объекта.
Атрибуты serialVersionUID разных классов независимы. Поэтому нет необходимости, чтобы разные классы имели уникальные значения.
Далее давайте узнаем, как использовать serialVersionUID на некоторых примерах.
Давайте начнем с создания сериализуемого класса и объявления идентификатора serialVersionUID :
Далее нам понадобятся два служебных класса: один для сериализации продукта Apple объекта в Строку, и другой для десериализации объекта из этой Строки:
Затем, используя эту Строку в качестве аргумента для метода десериализации, мы запускаем DeserializationUtility.java, который повторно собирает (десериализует) объект AppleProduct из заданной строки .
Полученный результат должен быть похож на этот:
Теперь давайте изменим константу serialVersionUID в AppleProduct.java, и попытка десериализации объекта продукта Apple из той же строки, созданной ранее. Повторный запуск DeserializationUtility.java должен генерировать этот вывод.
3. Совместимые изменения
Допустим, нам нужно добавить новое поле порт lightning в наш существующий Продукт Apple класс:
Давайте изменим нашу утилиту десериализации класса, чтобы напечатать значение этого нового поля:
Теперь, когда мы повторно запустим утилиту десериализации класса, мы увидим вывод, похожий на:
4. Серийная версия По Умолчанию
Если мы не определим serialVersionUID состояние для a Сериализуемый класс, то Java определит его на основе некоторых свойств самого класса, таких как имя класса, поля экземпляра и так далее.
Давайте определим простой Сериализуемый класс:
Если мы сериализуем экземпляр этого класса следующим образом:
Это выведет дайджест Base64 сериализованного двоичного файла:
Как и раньше, мы должны иметь возможность десериализовать этот экземпляр из дайджеста:
Однако некоторые изменения в этом классе могут нарушить совместимость сериализации. Например, если мы добавим поле private в этот класс:
А затем попробуйте десериализовать тот же дайджест Base64 в экземпляр класса, мы получим исключение InvalidClassException:
Из-за такого рода нежелательной несовместимости всегда рекомендуется объявлять serialVersionUID в Сериализуемых классах. Таким образом, мы можем сохранить или развить версию по мере развития самого класса.
5. Заключение
В этой краткой статье мы продемонстрировали использование константы serialVersionUID для облегчения управления версиями сериализованных данных.
Сериализация в Java
Зачем сериализация нужна?
В сегодняшнем мире типичное промышленное приложение будет иметь множество компонентов и будет распространено через различные системы и сети. В Java всё представлено в виде объектов; Если двум компонентам Java необходимо общаться друг с другом, то им необходим механизм для обмена данными. Есть несколько способов реализовать этот механизм. Первый способ это разработать собственный протокол и передать объект. Это означает, что получатель должен знать протокол, используемый отправителем для воссоздания объекта, что усложняет разработку сторонних компонентов. Следовательно, должен быть универсальный и эффективный протокол передачи объектов между компонентами. Сериализация создана для этого, и компоненты Java используют этот протокол для передачи объектов.
Рисунок 1 демонстрирует высоко-уровневое представление клиент-серверной коммуникации, где объект передаётся с клиента на сервер посредством сериализации. 
Рисунок 1.
Как сериализовать объект?
Для начала следует убедиться, что класс сериализуемого объекта реализует интерфейс java.io.Serializable как показано в листинге 1.
class TestSerial implements Serializable <
public byte version = 100;
public byte count = 0;
>
public static void main( String args[]) throws IOException <
FileOutputStream fos = new FileOutputStream( «temp.out» );
ObjectOutputStream oos = new ObjectOutputStream(fos);
TestSerial ts = new TestSerial();
oos.writeObject(ts);
oos.flush();
oos.close();
>
В листинге 2 показано сохранение состояния экземпляра TestSerial в файл с именем temp.out
Для воссоздания объекта из файла, необходимо применить код из листинга 3.
Формат сериализованного объекта
AC ED 00 05 73 72 00 0A 53 65 72 69 61 6C 54 65
73 74 A0 0C 34 00 FE B1 DD F9 02 00 02 42 00 05
63 6F 75 6E 74 42 00 07 76 65 72 73 69 6F 6E 78
70 00 64
public byte version = 100;
public byte count = 0;
Размер байтовой переменной один байт, и следовательно полный размер объекта (без заголовка) — два байта. Но размер сериализованного объекта 51 байт. Удивлены? Откуда взялись эти дополнительные байты и что они обозначают? Они добавлены сериализующим алгоритмом и необходимы для воссоздания объекта. В следующем абзаце будет подробно описан этот алгоритм.
Алгоритм сериализации Java
К этому моменту у вас уже должно быть достаточно знаний, чтобы сериализовать объект. Но как работает этот механизм? Алгоритм сериализации делает следующие вещи:
В листинге 6 указан пример охватывающий все возможные случаи сериализации
class parent implements Serializable <
int parentVersion = 10;
>
class contain implements Serializable <
int containVersion = 11;
>
public class SerialTest extends parent implements Serializable <
int version = 66;
contain con = new contain();
public int getVersion() <
return version;
>
public static void main( String args[]) throws IOException <
FileOutputStream fos = new FileOutputStream( «temp.out» );
ObjectOutputStream oos = new ObjectOutputStream(fos);
SerialTest st = new SerialTest();
oos.writeObject(st);
oos.flush();
oos.close();
>
>
AC ED 00 05 73 72 00 0A 53 65 72 69 61 6C 54 65
73 74 05 52 81 5A AC 66 02 F6 02 00 02 49 00 07
76 65 72 73 69 6F 6E 4C 00 03 63 6F 6E 74 00 09
4C 63 6F 6E 74 61 69 6E 3B 78 72 00 06 70 61 72
65 6E 74 0E DB D2 BD 85 EE 63 7A 02 00 01 49 00
0D 70 61 72 65 6E 74 56 65 72 73 69 6F 6E 78 70
00 00 00 0A 00 00 00 42 73 72 00 07 63 6F 6E 74
61 69 6E FC BB E6 0E FB CB 60 C7 02 00 01 49 00
0E 63 6F 6E 74 61 69 6E 56 65 72 73 69 6F 6E 78
70 00 00 00 0B
На рисунке 2 показан сценарий алгоритма сериализации.
Рисунок 2.
Заключение
В этой статье вы увидели как сериализовать объект, и узнали как работает алгоритм сериализации. Я надеюсь эта статья помогла вам лучше понять что происходит, когда вы сериализуете объект.
Об авторе
Sathiskumar Palaniappan имеет более чем 4-х летний опыт работы в IT-индестрии, и работает с Java технологиями более 3 лет. На данный момент он работает system software engineer в Java Technology Center, IBM Labs. Также имеет опыт работы в телекоммуникационной индустрии.
Что такое serialVersionUID в Java?
В этом уроке мы объясним, что такое serialVersionUID в Java, и рассмотрим пример сериализации и десериализации с его использованием.
Вступление
В этой статье мы обсудим концепцию, связанную с сериализацией и десериализацией в Java. Хотя иногда это рассматривается как ” часть черной магии API сериализации Java “, в этой статье мы увидим, что serialVersionUID на самом деле довольно прост и понятен.
Во-первых, мы остановимся на сериализации и десериализации, чтобы вспомнить некоторые важные идеи, которые нам понадобятся позже. После этого мы глубже погрузимся в serialVersionUID и покажем, что это такое и как это работает.
Наконец, в заключение мы покажем пример, который должен связать все воедино.
Сериализация и десериализация
Сериализация-это процесс сохранения состояния объекта таким образом, чтобы его можно было сохранить в базе данных, передать по сети, записать в файл и т.д. Как точно работает сериализация, выходит за рамки этой статьи, но в целом – она работает путем преобразования объекта в поток байтов, который затем может использоваться как любой другой поток информации, например, передаваемый через сетевой сокет.
Десериализация-это процесс, противоположный сериализации. Он принимает представление потока байтов объекта (например, из файла или сокета) и преобразует его обратно в объект Java, который находится внутри JVM.
Прежде чем можно будет выполнить сериализацию или десериализацию объекта, необходимо, чтобы этот объект (т. е. его класс) реализовал Сериализуемый интерфейс. Интерфейс Сериализуемый используется для “пометки” классов, которые могут быть (де)сериализованы.
Без класса, реализующего этот интерфейс, невозможно ни сериализовать, ни десериализовать объекты из этого класса. Выражаясь словами Сериализуемого Javadoc :
“Сериализуемость класса обеспечивается классом, реализующим интерфейс java.io.Serializable*.
Что такое serialVersionUID?
Если мы подумаем об этом, то это имеет большой смысл. Должен быть какой-то механизм определения того, соответствует ли отправленный объект полученному объекту. В противном случае может случиться, например, что перед сериализацией в класс объекта было внесено изменение, о котором получатель не знает.
При чтении объекта (т. е. десериализации) читатель может загрузить “новый” объект в “старое” представление. В лучшем случае это может иметь неприятные последствия, а в худшем-полное нарушение бизнес-логики.
Именно по этой причине serialVersionUID существует и обычно используется с всеми сериализуемыми объектами. Он используется для проверки того, что обе “версии” объекта (на стороне отправителя и получателя) совместимы, т. е. идентичны.
Как сгенерировать serialVersionUID?
В этом случае модификатор будет применяться только к текущему классу, а не к его подклассам, что является ожидаемым поведением; мы не хотим, чтобы на класс влияло что-либо еще, кроме него самого. Учитывая все сказанное, вот как может выглядеть правильно сконструированный serialVersionUID :
Наконец, если в классе присутствуют какие-либо переходные или статические поля, они будут игнорироваться во время процесса сериализации и будут нулевыми после десериализации.
Пример serialVersionUID
Git Essentials
Ознакомьтесь с этим практическим руководством по изучению Git, содержащим лучшие практики и принятые в отрасли стандарты. Прекратите гуглить команды Git и на самом деле изучите это!
Давайте вызовем этих двоих и понаблюдаем за выводом:
Наш метод DeserializeObject() загрузил сериализованный файл в JVM и успешно преобразовал его в Космический корабль объект.
Чтобы продемонстрировать проблему, упомянутую ранее в отношении управления версиями, давайте изменим значение serialVersionUID с 1L на 2L в нашем Космическом корабле классе.
Конечно, это приведет к:
Вывод
Надеюсь, теперь должно быть немного более ясно, в чем его назначение и как его правильно использовать в будущих проектах.
Что такое serialVersionUID и почему я должен его использовать?
Сериализуемый класс Foo не объявляет статический окончательный Поле serialVersionUID типа long
Что такое serialVersionUID и почему это важно? Пожалуйста, покажите пример, где отсутствующий serialVersionUID вызовет проблему.
ОТВЕТЫ
Ответ 1
Ответ 2
Если вы на самом деле используете сериализацию, это имеет значение, только если вы планируете хранить и извлекать объекты, используя сериализацию напрямую. serialVersionUID представляет версию вашего класса, и вы должны увеличивать ее, если текущая версия вашего класса не обратно совместима с его предыдущей версией.
В большинстве случаев вы, вероятно, не будете использовать сериализацию напрямую. Если это так, SerialVersionUID по умолчанию, щелкнув опцию быстрого исправления, и не беспокойтесь об этом.
Ответ 3
Я не могу упустить возможность подключить книгу Джоша Блоха » Эффективная Java» (2-е издание). Глава 11 является обязательным ресурсом по сериализации Java.
Ответ 4
Вы можете сказать Eclipse игнорировать эти предупреждения serialVersionUID:
Окно > Предпочтения > Java > Компилятоp > Ошибки/предупреждения > Проблемы с потенциальным программированием
Если вы не знаете, есть много других предупреждений, которые вы можете включить в этом разделе (или даже некоторые из них сообщаются как ошибки), многие из них очень полезны:
Ответ 5
serialVersionUID облегчает управление версиями сериализованных данных. Его значение хранится с данными при сериализации. При де-сериализации одна и та же версия проверяется, как сериализованные данные соответствуют текущему коду.
Если вы хотите изменить свои данные, вы обычно начинаете с serialVersionUID из 0 и ударяете его с каждым структурным изменением в ваш класс, который изменяет сериализованные данные (добавление или удаление непереходных полей).
Но хранение сериализованных данных за такой длительный промежуток времени не очень распространено. Гораздо чаще используется механизм сериализации для временной записи данных, например, кэш-памяти или отправки по сети другой программе с той же версией соответствующих частей кодовой базы.
В этом случае вы не заинтересованы в поддержании обратной совместимости. Вам нужно только убедиться, что базы кода, которые действительно обмениваются сообщениями, имеют одинаковые версии соответствующих классов. Чтобы облегчить такую проверку, вы должны поддерживать serialVersionUID так же, как и раньше, и не забывать обновлять ее при внесении изменений в свои классы.
Итак, чтобы помочь в этом использовании, платформа Java предлагает вам выбор, не устанавливающий serialVersionUID вручную. Вместо этого хэш структуры класса будет генерироваться во время компиляции и использоваться как id. Этот механизм гарантирует, что у вас никогда не будет разных структур классов с одним и тем же идентификатором, и поэтому вы не получите эти неудачные попытки сериализации во время выполнения, упомянутые выше.
Но есть обратная сторона для автоматической генерации стратегии id. А именно, что генерируемые идентификаторы для одного и того же класса могут отличаться между компиляторами (как упоминал выше, Джон Скит). Поэтому, если вы передаете сериализованные данные между кодом, скомпилированным с разными компиляторами, рекомендуется поддерживать идентификаторы вручную в любом случае.
И если вы обратно совместимы с вашими данными, как в упомянутом первом случае, вы также, вероятно, захотите сохранить идентификатор самостоятельно. Это для того, чтобы получить читаемые идентификаторы и иметь больший контроль над тем, когда и как они меняются.
Ответ 6
Что такое serialVersionUID и почему я должен его использовать?
SerialVersionUID является уникальным идентификатором для каждого класса, JVM использует его для сравнения версий класса, гарантирующих, что тот же класс, который использовался во время сериализации, загружался во время десериализации.
Указание одного дает больше контроля, хотя JVM генерирует его, если вы не укажете. Сгенерированное значение может отличаться для разных компиляторов. Кроме того, иногда вы просто хотите по какой-то причине запретить десериализацию старых сериализованных объектов [ backward incompatibility ], и в этом случае вам просто нужно изменить serialVersionUID.
вычисление serialVersionUID по умолчанию очень чувствительно к деталям класса, которые могут различаться в зависимости от реализаций компилятора, и, таким образом, может привести к неожиданному InvalidClassException во время десериализации.
Поэтому вы должны объявить serialVersionUID, потому что это дает нам больше контроля.
Эта статья имеет несколько положительных моментов по теме.
Ответ 7
В первоначальном вопросе были заданы вопросы «почему это важно» и «пример», в которых этот Serial Version ID будет полезен. Ну, я нашел один.
Ответ 8
Если вам никогда не понадобится сериализовать ваши объекты в массив байтов и отправить/сохранить их, вам не нужно беспокоиться об этом. Если да, то вы должны учитывать свой serialVersionUID, поскольку десериализатор объекта будет соответствовать его версии объекта, который имеет его загрузчик классов. Подробнее об этом читайте в спецификации языка Java.
Ответ 9
и в соответствующих методах вызовите myList.foo() вместо this.foo() (или super.foo() ). (Это не подходит во всех случаях, но все же довольно часто.)
Я часто вижу, как люди расширяют JFrame или такие, когда им действительно нужно только делегировать это. (Это также помогает для автозаполнения в среде IDE, поскольку JFrame имеет сотни методов, которые вам не нужны, когда вы хотите вызвать свои собственные в своем классе.)
Ответ 10
Чтобы понять значение поля serialVersionUID, нужно понимать, как работает сериализация/десериализация.
Когда объект класса Serializable сериализуется, Java Runtime связывает серийный номер версии (называемый serialVersionUID) с этим сериализованным объектом. В то время, когда вы десериализируете этот сериализованный объект, Java Runtime соответствует serialVersionUID сериализованного объекта с serialVersionUID этого класса. Если оба они равны, то только он переходит к дальнейшему процессу десериализации иначе бросает InvalidClassException.
Итак, мы заключаем, что для успешного завершения процесса сериализации/десериализации сериализованный объект serialVersionUID должен быть эквивалентен serialVersionUID этого класса. В случае, если программист явно указывает значение serialVersionUID в программе, то такое же значение будет связано с сериализованным объектом и классом, независимо от платформы сериализации и десериализации (например, сериализация может выполняться на платформе, например, с помощью окна или MS JVM и десериализация могут быть на другой платформе Linux с использованием Zing JVM).
Но в случае, если serialVersionUID не указан программистом, то, выполняя сериализацию \DeSerialization любого объекта, среда выполнения Java использует свой собственный алгоритм для ее вычисления. Этот алгоритм вычисления serialVersionUID варьируется от одной JRE к другой. Также возможно, что среда, в которой объект сериализуется, использует одну JRE (например: SUN JVM) и среду, в которой происходит десериализация, используется Linux Jvm (zing). В таких случаях serialVersionUID, связанный с сериализованным объектом, будет отличаться от serialVersionUID класса, рассчитанного в среде десериализации. В свою очередь десериализация не будет успешной. Поэтому, чтобы избежать таких ситуаций/проблем, программист должен всегда указывать serialVersionUID класса Serializable.
Ответ 11
Ответ 12
Что касается примера, когда недостающий serialVersionUID может вызвать проблему:
Этот класс POJO’s был упакован внутри банка EJB и внутри собственной банки в WEB-INF/lib веб-модуля. Они на самом деле одни и те же, но когда я упаковываю модуль EJB, я распаковываю этот баннер POJO, чтобы упаковать его вместе с модулем EJB.
Призыв к EJB был сбой при исключении ниже, потому что я не объявил его serialVersionUID :
Ответ 13
Сначала мне нужно объяснить сериализацию.
Сериализация позволяет преобразовать объект в поток для отправки этого объекта по сети ИЛИ сохранить в файл ИЛИ сохранить в БД для использования в письме.
Есть несколько правил для сериализации.
Объект является сериализуемым, только если его класс или его суперкласс реализуют интерфейс Serializable.
Все примитивные типы являются сериализуемыми.
Переходные поля (с модификатором переходного процесса) НЕ сериализуются (т.е. не сохраняются и не восстанавливаются). Класс, который реализует Serializable, должен отмечать переходные поля классов, которые не поддерживают сериализацию (например, файловый поток).
Статические поля (со статическим модификатором) не сериализуются.
Когда объект сериализуется, JAVA Runtime связывает серийный номер версии, который называется serialVersionID.
Где нам нужен serialVersionID: во время десериализации, чтобы убедиться, что отправитель и получатель совместимы с сериализацией. Если получатель загрузил класс с другим serialVersionID, то десериализация завершится с InvalidClassCastException.
Сериализуемый класс может объявить свой собственный serialVersionUID в явном виде, объявив поле с именем «serialVersionUID», которое должно быть статическим, конечным и типа long :.
Давайте попробуем это на примере.
Создать объект сериализации
ПРИМЕЧАНИЕ. Теперь измените serialVersionUID класса Employee и сохраните:
И выполнить класс Reader. Не выполнять класс Writer, и вы получите исключение.
Ответ 14
Среда сериализации связывает каждый сериализуемый класс с номером версии, называемым serialVersionUID, который используется во время десериализации, чтобы проверить, что отправитель и получатель сериализованного объекта загружают классы для этого объекта, которые совместимы с сериализацией.
Если получатель загрузил класс для объекта с другим идентификатором serialVersionUID, чем у соответствующего класса отправителя, тогда десериализация приведет к исключению InvalidClassException.
Ответ 15
Обычно я использую serialVersionUID в одном контексте: когда я знаю, что он покинет контекст Java VM.
Для всех остальных случаев я использую
Ответ 16
Если вы не хотите, чтобы это предупреждение появилось, используйте это:
Ответ 17
SerialVersionUID используется для управления версиями объекта. вы также можете указать serialVersionUID в своем файле класса. Следствием не указания serialVersionUID является то, что когда вы добавляете или изменяете любое поле в классе, тогда уже сериализованный класс не сможет восстановить, потому что serialVersionUID, сгенерированный для нового класса и для старого сериализованного объекта, будет другим. Процесс сериализации Java основан на правильном serialVersionUID для восстановления состояния сериализованного объекта и бросает java.io.InvalidClassException в случае несоответствия serialVersionUID
Ответ 18
Ответ 19
Зачем использовать SerialVersionUID внутри класса Serializable в Java?
Во время serialization среда выполнения Java создает номер версии для класса, чтобы впоследствии ее можно было де-сериализовать. Этот номер версии известен как SerialVersionUID в Java.
Ответ 20
Если вы хотите изменить огромное количество классов, в которых не было установленного параметра serialVersionUID, в то же время поддерживая совместимость со старыми классами, такие инструменты, как IntelliJ Idea, Eclipse, сокращаются по мере генерации случайных чисел и не работают на кучу файлов за один раз. Я прихожу к следующему bash script (я прошу прощения за пользователей Windows, подумайте о покупке Mac или конвертируйте в Linux), чтобы облегчить исправление проблемы serialVersionUID:
вы сохраните этот script, скажем, add_serialVersionUID.sh для вас
/bin. Затем запустите его в корневом каталоге вашего проекта Maven или Gradle, например:
Ответ 21
Этот вопрос очень хорошо документирован в «Эффективной Java» Джошуа Блоха. Очень хорошая книга и должна читать. Я расскажу о некоторых из следующих причин:
Сериализация выполняется с номером Serial для каждого сериализуемого класса. Этот номер называется serialVersionUID. Теперь за этим числом есть математика, и она выходит на основе полей/методов, определенных в классе. Для того же класса одна и та же версия генерируется каждый раз. Этот номер используется во время десериализации, чтобы убедиться, что отправитель и получатель сериализованного объекта загружают классы для этого объекта, которые совместимы с сериализацией. Если получатель загрузил класс для объекта с другим идентификатором serialVersionUID, чем у соответствующего класса отправителя, то десериализация приведет к исключению InvalidClassException.
Если класс сериализуем, вы также можете объявить свой собственный serialVersionUID явно, объявив поле с именем «serialVersionUID», которое должно быть статическим, окончательным и длинным. Большинство IDE, таких как Eclipse, помогают генерировать эту длинную строку.
Ответ 22
Каждый раз, когда объект сериализуется, объект имеет штамп с номером идентификатора версии для класса объекта. Этот идентификатор называется serialVersionUID и вычисляется на основе информации о структура классов. Предположим, что вы создали класс Employee, и у него есть версия id 333 (назначенная JVM). Теперь, когда вы будете сериализовывать объект этого класса (предположим, объект Employee), JVM присваивает ему UID как # 333.
Ответ 23
Вы сериализуете данные?
Собираетесь ли вы пойти в производство?
Если вы просто тестируете что-то с неважными/поддельными данными, не беспокойтесь об этом (если только вы не тестируете сериализацию напрямую).
Это вторая, третья и т.д. Версия?
По сути, если вы не обновите версию правильно, когда вы обновляете класс, который вам нужен для записи/чтения, вы получите сообщение об ошибке при попытке прочитать старые данные.
Ответ 24
у вас есть много разных копий вашей программы в разных местах (например, 1 сервер и 100 клиентов). Если вы измените свой объект, измените свой номер версии и забудете обновить один из этих клиентов, он будет знать, что он не способен к десериализации
Ответ 25
Во-первых, чтобы ответить на ваш вопрос, когда мы не объявляем SerialVersionUID в нашем классе, среда выполнения Java генерирует его для нас, но этот процесс чувствителен ко многим метаданным класса, включая количество полей, тип полей, модификатор доступа к полям, реализованный интерфейс по классам и т.д. Поэтому рекомендуется объявить это самим, и Eclipse предупреждает вас об этом.
Сериализация: мы часто работаем с важными объектами, состояние которых (данные в переменных объекта) настолько важно, что мы не можем рискнуть потерять их из-за сбоев питания/системы (или) сбоев сети в случае отправки состояния объекта другому машина. Решение этой проблемы называется «Постоянство», что просто означает сохранение (хранение/сохранение) данных. Сериализация является одним из многих других способов достижения постоянства (путем сохранения данных на диск/в память). При сохранении состояния объекта важно создать идентичность для объекта, чтобы иметь возможность правильно прочитать его обратно (десериализация). Этот уникальный идентификатор является ID SerialVersionUID.
Ответ 26
Всякий раз, когда вы проверяете код (этот конкретный класс) на системы управления версиями, вы можете просто изменить SerialVersionUID на метку версии, убедившись, что его длинный тип данных. Это также легко запомнить.



