Зачем генерировать длинный serialVersionUID вместо простого 1L?
когда класс реализует сериализуемый в Eclipse, у меня есть два варианта: добавить default serialVersionUID(1L) или сгенерирован serialVersionUID(3567653491060394677L). Я думаю, что первый из них круче, но много раз я видел людей, использующих второй вариант. Есть ли причина для создания long serialVersionUID?
10 ответов:
насколько я могу судить, это было бы только для совместимости с предыдущими релизами. Это было бы полезно только в том случае, если вы забыли использовать serialVersionUID раньше, а затем внесли изменения, которые, как вы знаете, должны быть совместимость но что вызывает прерывание сериализации.
посмотреть Java Serialization Spec для более подробной информации.
целью uid версии сериализации является отслеживание различных версий класса для выполнения допустимой сериализации объектов.
идея состоит в том, чтобы создать идентификатор, уникальный для определенной версии класса, который затем изменяется, когда в класс добавляются новые сведения, такие как новое поле, которое повлияет на структуру сериализованного объекта.
всегда использовать один и тот же идентификатор, например
1Lозначает, что в будущем, если определение класса изменяется, что вызывает изменения в структуре сериализованного объекта, там будет хороший шанс, что проблемы при попытке десериализации объекта.если идентификатор опущен, Java фактически вычислит идентификатор для вас на основе полей объекта, но я считаю, что это дорогостоящий процесс, поэтому предоставление одного вручную улучшит производительность.
вот несколько ссылок на статьи, которые обсуждают сериализацию и управление версиями классы:
- технические советы JDC: 29 февраля 2000(ссылка сломана по состоянию на февраль 2013 года)
- Откройте для себя секреты JAVA Serialization API
основной причиной для сгенерированного было бы сделать его совместимым с существующей версией класса, который уже имеет сохраненные копии.
"длинное" значение по умолчанию
serialVersionUIDзначение по умолчанию, как определено Спецификация Сериализации Java, вычисляется из поведения сериализации по умолчанию.Если вы не должны быть совместимы существующие битовые потоки, вы можете просто поставить
1Lтам и увеличить версию по мере необходимости, когда что-то меняется. То есть, когда версия сериализации по умолчанию измененного класса будет отличаться от версии по умолчанию старого класса.
вы абсолютно должны создать serialVersionUID каждый раз, когда вы определяете класс, который реализует
java.io.Serializable. Если вы этого не сделаете, один будет будет создан для вас автоматически, но это плохо. Автоматически сгенерированный serialVersionUID основан на сигнатурах метода вашего класса, поэтому если вы измените свой класс в будущем, чтобы добавить метод (например), десериализация "старых" версий класса завершится ошибкой. Вот что может случиться:
- создать первую версию класс, без определения serialVersionUID.
- сериализовать экземпляр класса в постоянное хранилище; a serialVersionUID автоматически генерируется для вас.
- измените класс, чтобы добавить новый метод, и повторно развернуть приложение.
- попытка десериализовать экземпляр, который был сериализован в шаге 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 генерируется случайным образом. На самом деле до тех пор, пока диапазон чисел равномерно распределен по всем возможным значениям длины, которые были бы штраф. Однако на самом деле это делается так:
http://docs.oracle.com/javase/6/docs/platform/serialization/spec/class.html#4100
единственное отличие, которое вы получаете с этим, вам не нужен источник случайного. Вы используете изменения в самом классе, чтобы изменить результат. Но согласно принципу Дирихле есть еще шанс на ошибку и столкновение. Это просто невероятно маловероятно. Так что удачи вам получить пиво из мне.
однако, даже если класс будет жить только в одной системе и одной кодовой базе, думая, что увеличение числа вручную дает вам нулевой шанс столкновений просто означает, что вы не понимаете людей. :)
ну, serialVersionUID является исключением из правила ,что "статические поля не сериализуются". ObjectOutputStream записывает каждый раз значение serialVersionUID в выходной поток. ObjectInputStream считывает его обратно, и если значение, считанное из потока, не согласуется со значением serialVersionUID в текущей версии класса, то он выдает исключение InvalidClassException. Кроме того, если serialVersionUID официально не объявлен в классе для сериализации, компилятор автоматически добавляет его со значением, созданным на основе полей, объявленных в классе.
потому что во многих случаях идентификатор по умолчанию не является уникальным. поэтому мы создаем id для создания уникальной концепции.
чтобы добавить к ответу @ David Schmitts, как правило, я всегда буду использовать значение по умолчанию 1L из соглашения. Мне только пришлось вернуться и изменить некоторые из них несколько раз, но я знал, что когда я сделал изменение и обновил номер по умолчанию по одному каждый раз.
в моей текущей компании им требуется автоматически сгенерированный номер, поэтому я использую его для соглашения, но я предпочитаю значение по умолчанию. Мое мнение, если это не Соглашение, где вы работаете, используйте значение по умолчанию, если вы не думаете, что вы по какой-то причине будет постоянно меняться структура ваших сериализованных классов.
Comments