Зачем генерировать длинный serialVersionUID вместо простого 1L?

StackOverflow https://stackoverflow.com/questions/888335

Вопрос

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

Это было полезно?

Решение

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

Смотрите на Спецификация сериализации Java для получения более подробной информации.

Другие советы

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

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

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

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

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

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

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

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

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

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

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

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

Когда вы используете 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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top