Когда класс реализует Serializable в Eclipse, у меня есть два варианта: добавьте default serialVersionUID(1L)
или сгенерированный serialVersionUID(3567653491060394677L)
. Я думаю, что первый из них более холодный, но много раз я видел людей, использующих второй вариант. Есть ли причина генерации long serialVersionUID
?
Зачем генерировать длинный serialVersionUID вместо простого 1L?
Ответ 1
Насколько я могу судить, это было бы только для совместимости с предыдущими выпусками. Это было бы полезно, если раньше вы пренебрегали использованием serialVersionUID, а затем внесли изменения, которые, как вы знаете, должны быть совместимы, но это приводит к разрыву сериализации.
Подробнее см. Java Serialization Spec.
Ответ 2
Целью UID для сериализации является отслеживание различных версий класса для выполнения правильной сериализации объектов.
Идея состоит в том, чтобы сгенерировать идентификатор, который является уникальным для определенной версии класса, который затем изменяется, когда в класс добавляются новые детали, такие как новое поле, которое влияет на структуру сериализованного объекта.
Всегда использовать один и тот же идентификатор, например 1L
, означает, что в будущем, если определение класса будет изменено, что приведет к изменениям структуры сериализованного объекта, будет хороший шанс, что проблемы при попытке десериализации объект.
Если идентификатор опущен, Java фактически рассчитает идентификатор для вас на основе полей объекта, но я считаю, что это дорогостоящий процесс, поэтому предоставление одного вручную приведет к повышению производительности.
Вот несколько ссылок на статьи, которые обсуждают сериализацию и управление версиями классов:
- JDC Tech Tips: 29 февраля 2000 г. (ссылка не действительна с февраля 2013 г.)
- Откройте секреты Java Serialization API
Ответ 3
Основная причина сгенерированного заключается в том, чтобы сделать его совместимым с существующей версией класса, который уже сохранил копии.
Ответ 4
"длинное" значение по умолчанию serialVersionUID
- это значение по умолчанию, определенное в Java Serialization Specification, рассчитанное из поведения сериализации по умолчанию.
Таким образом, если вы добавите номер версии по умолчанию, ваш класс будет (дезактивирован) сериализоваться быстрее, если ничто не будет структурно изменено, но вам придется позаботиться о том, что если вы измените класс (добавить/удалить поля), вы также обновите серийный номер.
Если вам не нужно быть совместимым с существующими потоками битов, вы можете просто поместить 1L
туда и при необходимости увеличивать версию, когда что-то меняется. То есть, когда стандартная сериализация версии измененного класса будет отличаться от стандартной версии старого класса.
Ответ 5
Вы абсолютно должны создавать serialVersionUID каждый раз, когда вы определяете
класс, реализующий java.io.Serializable
. Если вы этого не сделаете,
создаваться для вас автоматически, но это плохо. Автогенерация
serialVersionUID основан на методах подписи вашего класса, поэтому
если вы измените свой класс в будущем, чтобы добавить метод (например),
десериализация "старых" версий класса не удастся. Вот что
может случиться:
- Создайте первую версию своего класса, не определяя serialVersionUID.
- Сериализовать экземпляр вашего класса в постоянном хранилище; serialVersionUID автоматически генерируется для вас.
- Измените свой класс, чтобы добавить новый метод, и повторно разверните приложение.
- Попытка десериализовать экземпляр, который был сериализован на шаге 2, но теперь он терпит неудачу (когда он будет успешным), поскольку он имеет различные автоматически генерируемые serialVersionUID.
Ответ 6
Если вы не укажете serialVersionUID, то Java сделает его "на лету". Сгенерированный serialVersionUID - это число. Если вы измените что-то в своем классе, что на самом деле не делает ваш класс несовместимым с предыдущими сериализованными версиями, но изменяет хеш, тогда вам нужно использовать сгенерированный очень большой номер serialVersionUID (или "ожидаемый" номер из сообщения об ошибке), В противном случае, если вы все отслеживаете сами, 0, 1, 2... лучше.
Ответ 7
Когда вы используете serialVersionUID (1L), а не генерируете serialVersionUID (3567653491060394677L), вы что-то говорите.
Вы говорите, что на 100% уверены, что ни одна система, которая когда-либо коснется этого класса, имеет несовместимую сериализованную версию этого класса с номером версии 1.
Если вы можете придумать любое оправдание того, что сериализованная история версий будет неизвестна, это может быть трудно сказать с уверенностью. В этом случае успешный класс будет поддерживаться многими людьми, жить во многих проектах и находиться во многих системах.
Вы можете мучиться из-за этого. Или вы можете играть в лотерею, надеясь проиграть. Если вы создадите версию, у вас есть крошечный шанс, что все пойдет не так. Если вы предполагаете "Эй, я уверен, никто не использовал еще 1", ваши шансы больше крошечных. Это именно потому, что мы все думаем, что 0 и 1 классны, что у вас есть более высокие шансы нанести им удар.
-
Когда вы создаете serialVersionUID (3567653491060394677L), а не используете serialVersionUID (1L), вы что-то говорите.
Вы говорите, что люди могут вручную создать или сгенерировать другие номера версий в истории этого класса, и вам все равно, потому что Longs заполняют большие числа.
В любом случае, если вы не знаете историю номеров версий, используемых при сериализации класса во всей вселенной, где она существует или когда-либо существовала, вы получаете шанс. Если у вас есть время, чтобы сделать 100% уверенным, что 1 это AOK, пойдите для этого. Если это много работает, продолжайте и слепо сгенерировать номер. Вы, скорее всего, выиграете в лотерею, чем заблуждаетесь. Если да, дайте мне знать, и я куплю вам пиво.
Со всеми этими разговорами о том, чтобы играть в лотерею, я, возможно, дал вам впечатление, что serialVersionUID генерируется случайным образом. Фактически, если диапазон чисел равномерно распределен по любому возможному значению Long, это будет хорошо. Однако это действительно так:
http://docs.oracle.com/javase/6/docs/platform/serialization/spec/class.html#4100
Единственное различие, которое вы получаете с этим, - вам не нужен источник случайного. Вы используете изменения в классе, чтобы изменить результат. Но в соответствии с принципом голубины все еще есть шанс, что он может пойти не так и столкнуться. Это просто невероятно маловероятно. Так что удача в том, чтобы выпить пива из меня.
Однако, даже если класс будет жить только в одной системе и одной базе кода, думая, что увеличение количества вручную дает вам нулевой шанс столкновения, просто означает, что вы не понимаете людей.:)
Ответ 8
Ну, serialVersionUID является исключением из правила, что "статические поля не сериализуются". ObjectOutputStream записывает каждый раз значение serialVersionUID в выходной поток. ObjectInputStream считывает его обратно, и если значение, считанное из потока, не согласуется с значением serialVersionUID в текущей версии класса, тогда оно выдает InvalidClassException. Более того, если не существует serialVersionUID, официально объявленного в классе, который будет сериализован, компилятор автоматически добавит его со значением, сгенерированным на основе полей, объявленных в классе.
Ответ 9
Потому что во многих случаях идентификатор по умолчанию не уникален. поэтому мы создаем идентификатор для создания уникальной концепции.