private static final long serialversionuid 1l что это

Что такое 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 для облегчения управления версиями сериализованных данных.

Источник

Что такое 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 в нашем Космическом корабле классе.

Конечно, это приведет к:

Вывод

Надеюсь, теперь должно быть немного более ясно, в чем его назначение и как его правильно использовать в будущих проектах.

Источник

Что такое сериализация? Все, Что Вам Нужно Знать О Сериализации Java, Объясняется На Примере

В предыдущей статье мы рассмотрели 5 различных способов создания объектов на java, я объяснил, как это сделать… Помеченный java, сериализация.

Мы будем использовать приведенный ниже объект Employee class в качестве примера для объяснения

Что такое Сериализация и Десериализация

В Java мы создаем несколько объектов, которые живут и умирают соответственно, и каждый объект, безусловно, умрет, когда JVM умрет, но иногда мы можем захотеть повторно использовать объект между несколькими JVM или мы можем захотеть перенести объект на другую машину по сети.

Ну, сериализация позволяет нам преобразовать состояние объекта в поток байтов, который затем можно сохранить в файл на локальном диске или отправить по сети на любую другую машину. И десериализация позволяет нам обратить процесс вспять, что означает повторное преобразование сериализованного потока байтов в объект.

Проще говоря, объект сериализация – это процесс сохранения состояния объекта в последовательности байтов, а десериализация – это процесс восстановления объекта из этих байтов. Как правило, полный процесс называется сериализацией но я думаю, что лучше классифицировать их как отдельные для большей ясности.

Процесс сериализации не зависит от платформы, объект, сериализованный на одной платформе, может быть десериализован на другой платформе.

Чтобы сериализовать и десериализовать наш объект в файл, нам нужно вызвать ObjectOutputStream.writeObject() и ObjectInputStream.readObject() как это сделано в следующем коде:

Сериализуемыми могут быть только классы, реализующие сериализуемость

Аналогично клонируемому интерфейсу для Клонирование Java в сериализации у нас есть один сериализуемый интерфейс маркера, который работает как флаг для JVM. Любой класс, который реализует Сериализуемый интерфейс напрямую или через своего родителя, может быть сериализован, а классы, которые не реализуют |/Сериализуемый не может быть сериализован.

Процесс сериализации Java по умолчанию полностью рекурсивен, поэтому всякий раз, когда мы пытаемся сериализовать один объект, процесс сериализации пытается сериализовать все поля (примитивные и ссылочные) с помощью нашего класса (кроме static и переходные поля).

Почему Сериализуемый не реализуется объектом?

Класс Объект не реализует Сериализуемый интерфейс, потому что мы, возможно, не захотим сериализовать все объекты, например, сериализация потока не имеет никакого смысла, потому что поток, запущенный в моей JVM, будет использовать память моей системы, сохранять ее и пытаться запустить ее в вашей JVM, не будет иметь смысла.

Переходные и статические поля не сериализуются

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

Что такое serialVersionUID и почему мы должны его объявлять?

Если мы изменим структуру нашего класса, например, удалим/добавим поля, номер версии также изменится, и в соответствии с JVM наш класс не совместим с версией класса сериализованного объекта. Вот почему мы получаем исключение, но если вы действительно думаете об этом, почему оно должно быть выброшено только потому, что я добавил поле? Нельзя ли просто установить для поля значение по умолчанию, а затем записать его в следующий раз?

Настройка сериализации и десериализации с помощью методов writeObject и readObject

JVM имеет полный контроль над сериализацией объекта в процессе сериализации по умолчанию, но у процесса сериализации по умолчанию есть много недостатков, некоторые из которых:

Но мы можем переопределить это поведение сериализации по умолчанию внутри нашего класса Java и предоставить некоторую дополнительную логику для улучшения обычного процесса. Это можно сделать, предоставив два метода writeObject и readObject внутри класса, который мы хотим сериализовать:

Объявление обоих методов как частных необходимо (публичные методы не будут работать), поэтому вместо JVM их больше ничто не сможет увидеть. Это также доказывает, что ни один метод не наследуется, не переопределяется и не перегружается. JVM автоматически проверяет эти методы и вызывает их во время процесса сериализации-десериализации. JVM может вызывать эти частные методы, но другие объекты не могут, таким образом, целостность класса сохраняется, и протокол сериализации может продолжать работать в обычном режиме.

Вызов ObjectOutputStream.writeObject() или ObjectInputStream.readObject() запускает протокол сериализации. Сначала объект проверяется, чтобы убедиться, что он реализует Сериализуемый а затем проверяется, предоставлен ли какой-либо из этих частных методов. Если они предоставлены, класс stream передается в качестве параметра этим методам, предоставляя коду контроль над его использованием.

Мы можем вызвать ObjectOutputStream.defaultWriteObject() и ObjectInputStream.defaultReadObject() из этих методов, чтобы получить логику сериализации по умолчанию. Эти вызовы делают то, на что они похожи – они выполняют запись и чтение сериализованного объекта по умолчанию, что важно, потому что мы не заменяем обычный процесс, мы только добавляем к нему.

Эти частные методы можно использовать для любой настройки, которую вы хотите выполнить в процессе сериализации, например, шифрование может быть добавлено к выходным данным, а дешифрование – к входным (обратите внимание, что байты записываются и считываются открытым текстом без каких-либо запутываний вообще). Их можно использовать для добавления дополнительных данных в поток, возможно, кода управления версиями компании, возможности поистине безграничны.

Помимо методов writeObject и readObject, мы также можем использовать другие магические методы сериализации для получения некоторых дополнительных функций.

Остановка сериализации и десериализации

Однако это является нарушением принципа замены Лискова. И Методы writeReplace и readResolve могут быть использованы для достижения одноэлементного поведения. Эти методы используются для того, чтобы объект мог предоставить альтернативное представление для самого себя в потоке объектов. Проще говоря, readResolve можно использовать для изменения данных, которые десериализуются с помощью метода readObject, а writeReplace можно использовать для изменения данных, которые сериализуются с помощью writeObject.

Вывод

Я также написал серию статей, объясняющих номера пунктов 74-78 Эффективной Java, в которых дополнительно обсуждается, как можно улучшить процесс сериализации Java, пожалуйста, продолжайте и прочитайте их, если хотите.

Вы можете найти полный исходный код этой статьи в этом Репозитории Github и, пожалуйста, не стесняйтесь оставлять свои ценные отзывы.

Источник

Сериализация объектов

Сериализация объекта представляет процесс перевода какой-либо структуры данных в последовательность битов. Обратной к операции сериализации является операция десериализации, т.е. восстановление начального состояния структуры данных из битовой последовательности. Существует два способа сериализации объекта : стандартная сериализация java.io.Serializable и «расширенная» сериализация java.io.Externalizable.

Интерфейс java.io.Serializable

При использовании Serializable применяется стандартный алгоритм сериализации, который с помощью рефлексии (Reflection API) выполняет

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

Для выполнения десериализации под объект выделяется память, после чего его поля заполняются значениями из потока. Конструктор объекта при этом не вызывается. Однако при десериализации будет вызван конструктор без параметров родительского несериализуемого класса, а его отсутствие повлечёт ошибку десериализации.

Интерфейс java.io.Externalizable

При реализации интерфейса Externalizable вызывается пользовательская логика сериализации. Способ сериализации и десериализации описывается в методах writeExternal и readExternal. Во время десериализации вызывается конструктор без параметров, а потом уже на созданном объекте вызывается метод readExternal.

Расширенный алгоритм сериализации может быть использован, если данные содержат «конфиденциальную» информацию. В этом случае имеет смысл шифровать сериализуемые данные и дешифровать их при десерилизации, что требует реализацию собственного алгоритма.

Где используется сериализация Serializable?

Сериализация была введена в JDK 1.1 и позволяет преобразовать отдельный объект или группу объектов в поток битов для передачи по сети или для сохранения в файл. И как было сказано выше, данный массив байтов или поток битов, можно обратно преобразовать в объекты Java. Главным образом это происходит автоматически благодаря классам ObjectInputStream и ObjectOutputStream.

Класс сериализации Person

В следующем листинге показан класс Person, реализующий интерфейс Serializable.

Далее класс Person будет использоваться в примерах, чтобы показать дополнительные возможности, связанные с сериализацией Java-объектов.

Модификатор поля transient

Использование при описании поля класса модификатора transient позволяет исключить указанное поле из сериализации. Это бывает полезно для секретных (пароль) или не особо важных данных. Если, например, при описании объекта Person включить следующее поле address

то в результате сериализации и десериализации адрес объекта принимает значение по умолчанию или будет null.

Модификатор transient действует только на стандартный механизм сериализации Serializable. При использовании Externalizable никто не мешает сериализовать это поле, равно как и использовать его для определения других полей.

Модификатор поля static

При стандартной сериализации поля, имеющие модификатор static, не сериализуются. Соответственно, после десериализации это поле значения не меняет. При использовании реализации Externalizable сериализовать и десериализовать статическое поле можно, но не рекомендуется этого делать, т.к. это может сопровождаться трудноуловимыми ошибками.

Модификатор поля final

Поля с модификатором final сериализуются как и обычные. За одним исключением – их невозможно десериализовать при использовании Externalizable, поскольку final-поля должны быть инициализированы в конструкторе, а после этого в readExternal изменить значение этого поля будет невозможно. Соответственно, если необходимо сериализовать объект с final-полем неоходимо использовать только стандартную сериализацию.

Пример тестирования сериализации и десериализации

Для тестирования сериализации и десериализации объекта Person будем использовать юнит-тест JUnit, в котором создадим 2 объекта, запишем объекты в файл, после чего восстановим их. Более подробно об использовании JUnit сказано на странице Тестирование программы.

В примере ничего нового или удивительного не представлено – это основы сериализации, которые желательно знать, особенно при разработке WEB-приложений.

Переопределение сериализации в интерфейсе Serializable

Если у сериализуемого объекта реализован один из следующих методов, то механизм сериализации будет использовать его, а не метод по умолчанию :

Ниже приводятся примеры использования данных методов.

Сериализация не безопасна

Двоичный формат сериализации полностью документирован и обратим. Для того, чтобы определить параметры объекта и его значения, достаточно просто вывести содержимое сериализованного потока в консоль. Это имеет некоторые связанные с безопасностью неприятные последствия. Например, при выполнении удаленного вызова метода с помощью RMI все закрытые поля пересылаемых по сети объектов выглядят в потоке сокета почти как обычный текст, что, конечно же, нарушает даже самые простые правила безопасности.

К счастью разработчиков Java Serialization API позволяет «вклиниться» в процесс сериализации, и изменить (или запутать) поля данных как перед сериализацией, так и после десериализации. Это можно сделать, определив методы writeObject, readObject объекта Serializable.

Изменение сериализованных данных, writeObject, readObject

Чтобы изменить процесс сериализации в классе Person реализуем метод writeObject. Для модифицирования процесса десериализации определим в том же классе метод readObject. При реализации этих методов необходимо корректно восстановить данные.

Сериализация и рефакторинг кода

Сериализация позволяет вносить небольшие изменения в структуру класса, так что даже после рефакторинга класс ObjectInputStream по-прежнему будет с ним прекрасно работать. К наиболее важным изменениям, с которыми спецификация Java Object Serialization может справляться автоматически:

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

Рефакторинг сериализованного класса

Для тестирования сериализации с измененной структурой класса Person на основе предыдущего примера необходимо проделать следующие предварительные шаги :

Листинг изменений класса Person

Теперь можно выполнить тест testSerialization класса JUnitPerson и увидеть, что тест прошел успешно, т.е. класс ObjectInputStream прочитал данные и объект был восстановлен корректно. При желании можно в конце кода testSerialization вставить строку

чтобы убедиться, что значения объекта восстановлены правильно, и что параметр gender равен null.

Проверка десериализованного объекта, ObjectInputValidation и validateObject

Если есть необходимость выполнения контроля за значениями десериализованного/восстановленного объекта, то можно использовать интерфейс ObjectInputValidation с переопределением метода validateObject. В следующем листинге представлены изменения, которые следует внести в описание класса Person, чтобы контролировать возраст.

Если вызвать метод validateObject после десериализации объекта, то будет вызвано исключение InvalidObjectException при значении возраста за пределами 39. 60.

Подписывание сериализованных данных

Чтобы убедиться, что данные не были изменены в файле или при пересылке по сети их можно «подписать». Несмотря на то, что управление подписями реализовать можно и с помощью методов writeObject и readObject, для этого есть более подходящий способ.

Если требуется зашифровать и подписать объект, то проще всего поместить его в оберточный класс javax.crypto.SealedObject и/или java.security.SignedObject. Данные классы являются сериализуемыми, поэтому при оборачивании объекта в SealedObject создается подобие «подарочной упаковки» вокруг исходного объекта. Для шифрования необходимо создать симметричный ключ, управление которым должно осуществляться отдельно. Аналогично, для проверки данных можно использовать класс SignedObject, для работы с которым также нужен симметричный ключ, управляемый отдельно. Эти два объекта позволяют упаковывать и подписывать сериализованные данные, не отвлекаясь на детали проверки и шифрования цифровых подписей.

Листинг теста подписи объекта

Прокси-класс для сериализации

Иногда класс может включать элемент, который позволяет получить значения отдельных полей класса по определенному алгоритму. В этих случаях необязательно сериализовывать весь объект. Можно было бы пометить восстанавливаемые поля как «транзитные». Однако в классе всё равно требуется явно указывать код (определять метод), который при обращении к полю каждый раз проверял бы его инициализацию. Для этих целей лучше использовать специальный прокси-класс, из которого можно восстановить объект.

Листинг прокси-класса

В прокси-классе определим метод readResolve, которой будет вызываться во время десериализации объекта, чтобы вернуть объект-замену. Конструктор прокси-класса будет упаковывать объект PersonY во внутреннее поле data.

Класс PersonY создадим на основе базового класса Person с добавлением метода writeReplace следующего вида :

Вместе методы writeReplace и readResolve позволяют классу PersonY упаковывать все данные (или их наиболее важную часть) в объект класса PersonProxy, помещать его в поток и затем распаковать его при десериализации.

Пример тестирования прокси-класса JUnitPersonProxy

Особенности сериализации Date

Если объект сериализации включает поля типа Date, то здесь следует, при необходимости, учитывать временной сдвиг между различными регионами. В противном случае может возникнуть ситуация, при которой на сервере будет создан объект Date с одним временем в определенной TimeZone, а на клиенте он будет десериализован с другой TimeZone. В зависимости от времени создания игнорирование TimeZone может привести к изменению даты. Решение данной проблемы представлено на странице описания TimeZone.

Использование сериализации

Технология RMI (Java Remote Method Invocation), построенная на сериализации, позволяет java-приложению, запущенному на одной виртуальной машине, вызвать методы объекта, работающего на другой виртуальной машине JVM (Java Virtual Machine).

Скачать пример Serialization

Исходный код рассмотренного примера Serialization в виде проекта Eclipse можно скачать здесь (15.0 Kб).

Источник

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

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