Зачем генерировать длинный serialVersionUID вместо простого 1L? - PullRequest
200 голосов
/ 20 мая 2009

Когда класс реализует Serializable в Eclipse, у меня есть две опции: добавить по умолчанию serialVersionUID(1L) или сгенерировать serialVersionUID(3567653491060394677L). Я думаю, что первый круче, но много раз я видел людей, использующих второй вариант. Есть ли причина генерировать long serialVersionUID?

Ответы [ 10 ]

82 голосов
/ 20 мая 2009

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

Подробнее см. Java Serialization Spec .

68 голосов
/ 20 мая 2009

Цель UID версии сериализации состоит в том, чтобы отслеживать различные версии класса для выполнения действительной сериализации объектов.

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

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

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

Вот несколько ссылок на статьи, которые обсуждают сериализацию и управление версиями классов:

17 голосов
/ 20 мая 2009

Основная причина для сгенерированного - сделать его совместимым с существующей версией класса, в которой уже есть постоянные копии.

13 голосов
/ 20 мая 2009

«Длинное» значение по умолчанию serialVersionUID является значением по умолчанию, определенным Спецификацией Java-сериализации , рассчитанным по стандартному поведению сериализации.

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

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

9 голосов
/ 23 марта 2011

Вы обязательно должны создавать serialVersionUID каждый раз, когда определяете класс, который реализует java.io.Serializable. Если вы этого не сделаете, один будет быть создан для вас автоматически, но это плохо. Автоматически генерируется serialVersionUID основан на сигнатурах методов вашего класса, поэтому если вы измените свой класс в будущем, чтобы добавить метод (например), десериализация «старых» версий класса не удастся. Вот что может случиться:

  1. Создайте первую версию вашего класса, не определяя serialVersionUID.
  2. Сериализация экземпляра вашего класса в постоянное хранилище; serialVersionUID генерируется автоматически для вас.
  3. Измените ваш класс, чтобы добавить новый метод, и повторно разверните ваше приложение.
  4. Попытка десериализации экземпляра, который был сериализован на шаге 2, но теперь он завершается неудачно (когда это должно произойти), потому что у него есть другой автоматически сгенерированный serialVersionUID.
6 голосов
/ 20 мая 2009

Если вы не укажете serialVersionUID, то Java сделает его на лету. Сгенерированный serialVersionUID - это тот номер. Если вы изменяете что-то в своем классе, что на самом деле не делает ваш класс несовместимым с предыдущими сериализованными версиями, но меняет хеш, то вам нужно использовать сгенерированный serialVersionUID с очень большим числом (или «ожидаемое» число из сообщения об ошибке) , В противном случае, если вы все отслеживаете сами, лучше 0, 1, 2 ...

4 голосов
/ 19 августа 2013

Когда вы используете serialVersionUID (1L) вместо генерации serialVersionUID (3567653491060394677L), вы что-то говорите.

Вы говорите, что на 100% уверены, что ни одна система, которая когда-либо будет касаться этого класса, не имеет несовместимой сериализованной версии этого класса с номером версии 1.

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

Вы можете мучиться из-за этого. Или вы можете сыграть в лотерею в надежде проиграть. Если вы генерируете версию, у вас есть небольшой шанс, что что-то пойдет не так. Если вы предполагаете: «Эй, я уверен, никто еще не использовал 1», ваши шансы больше, чем крошечные. Именно потому, что мы все думаем, что 0 и 1 - это круто, у вас больше шансов попасть в них.

-

Когда вы генерируете serialVersionUID (3567653491060394677L), а не используете serialVersionUID (1L), вы что-то говорите.

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

В любом случае, если вы полностью не знаете историю номеров версий, использованных при сериализации класса во всей вселенной, где он существует или будет существовать, вы рискуете. Если у вас есть время, чтобы убедиться на 100%, что 1 - это AOK, сделайте это. Если это много работы, идти вперед и слепо генерировать число. Вы скорее выиграете в лотерею, чем ошибетесь. Если да, дайте мне знать, и я куплю вам пиво.

После всего этого разговора об игре в лотерею у меня могло сложиться впечатление, что serialVersionUID генерируется случайным образом. Фактически, пока диапазон чисел равномерно распределен по каждому возможному значению Long, это было бы хорошо. Однако на самом деле это делается так:

http://docs.oracle.com/javase/6/docs/platform/serialization/spec/class.html#4100

Единственное отличие, которое вы получаете, заключается в том, что вам не нужен источник случайных чисел. Вы используете изменения в самом классе, чтобы изменить результат. Но по принципу «голубиных отверстий» все еще есть вероятность, что он может пойти не так и столкнуться. Это невероятно невероятно. Так что удачи в извлечении пива из меня.

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

1 голос
/ 11 декабря 2012

Ну, serialVersionUID является исключением из правила, согласно которому «статические поля не сериализуются». ObjectOutputStream каждый раз записывает значение serialVersionUID в выходной поток. ObjectInputStream считывает его обратно, и если значение, считанное из потока, не соответствует значению serialVersionUID в текущей версии класса, то оно генерирует исключение InvalidClassException. Более того, если нет serialVersionUID, официально объявленного в сериализуемом классе, компилятор автоматически добавляет его со значением, созданным на основе полей, объявленных в классе.

0 голосов
/ 22 мая 2018

Чтобы добавить в ответ @David Schmitts, я бы всегда использовал стандартное значение 1L вне соглашения. Я только должен был вернуться и изменить некоторые из них несколько раз, но я знал это, когда вносил изменения и обновлял номер по умолчанию по одному каждый раз.

В моей нынешней компании им требуется автоматически сгенерированный номер, поэтому я использую его для соглашения, но я предпочитаю значение по умолчанию. Я считаю, что если это не соглашение, в котором вы работаете, используйте значение по умолчанию, если только вы не думаете, что по какой-то причине вы будете постоянно менять структуру сериализованных классов.

0 голосов
/ 16 сентября 2011

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

...