Что означает 1L serialVersionUID? Когда я могу использовать это значение по умолчанию 1L?

Существует 3 способа определения serialVersionUID:

1. private static final long serialVersionUID = 1L; (Default)
2. private static final long serialVersionUID = -8940196742313994740L; (Generated)
3. Don't define serialVersionUID and let the JVM define it at runtime. @Lance Java

Но я не понимаю первого пути!

Я уже видел это, что кто-то определяет "serialVersionUID = 1L" для всех java-классов в исходном коде.

В чем смысл? Это полезно?

Если все классы имеют один и тот же serialVersionUID 1L, нет ли проблем?

+17
18 февр. '14 в 10:29
источник поделиться
8 ответов

В чем смысл? Это полезно?

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

Если все классы имеют один и тот же serialVersionUID 1L, нет ли проблем?

Нет - serialVersionUID для каждого класса.

+12
18 февр. '14 в 10:36
источник

Это объясняет здесь:

serialVersionUID является универсальным идентификатором версии для класса Serializable. Deserialization использует это число, чтобы гарантировать, что загруженный класс точно соответствует сериализованному объекту. Если совпадение не найдено, генерируется исключение InvalidClassException.


Из javadoc:

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


Полезные ссылки

+8
18 февр. '14 в 10:34
источник

JVM будет бросать InvalidClassException, если serialVersionUID сериализованного объекта не соответствует serialVersionUID класса, который десериализуется как.

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

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

+6
18 февр. '14 в 10:35
источник

Да, я видел код, который также определил serialVersionUID. Я думаю, что это плохая идея.

В этом контексте есть только одно "отличное" значение для поля serialVersionUID; то есть нуль... 0L. Zero означает "вычислить идентификатор версии во время выполнения, применяя стандартный алгоритм" на основе фактического класса, который вы сериализуете/десериализуете. Это означает, что всякий раз, когда изменяется эффективная сигнатура сериализации кода, код сериализации/десериализации будет использовать другой идентификатор версии. С точки зрения безопасности (большой картины), это самая безопасная вещь, хотя она также несколько неэффективна и по преимуществу более хрупкая.

В чем смысл?

1L не имеет особого значения. Это просто число, которое будет соответствовать 1L как "другой" идентификатор версии.

На мой взгляд, вам лучше использовать либо 0L, либо номер версии, которая была (в какой-то момент) сгенерирована с использованием стандартного алгоритма.

  • Если вы используете 0L, вы получаете определенные исключения десериализации, если классы меняются способами, которые могут быть источником проблем. Если вам это нужно, это хорошо.

  • С другой стороны, вы используете сгенерированный идентификатор версии, вы (программист) можете принять собственное решение о том, когда нужно восстановить идентификатор. И когда вы решите регенерировать, идентификатор изменится только в том случае, если подпись класса изменилась. (Если представление классов и т.д. Не изменилось, регенерированная подпись должна быть идентичной оригинальной!) И когда идентификатор изменится, вы можете подумать о том, добавлять ли пользовательские методы ( "readObject" и т.д.), Чтобы справиться с несовместимостью.

  • Однако, если вы используете 1L, вы не можете определить, нужно ли изменять идентификатор версии, не проверяя историю вашего кода и сравнивая старые/новые версии классов... до тех пор, пока вам нужно.

Это полезно?

Это зависит от того, что вы считаете "полезным". Если вы считаете, что это хорошая вещь, чтобы жестко подключить идентификатор версии, чтобы "доверять мне, это нормально", тогда полезно использовать 1L.


Мое воспоминание о том, что некоторые версии Eclipse предлагают 1L как одну из возможных автокоррекций для отсутствующего предупреждения поля serialVersionUID. Вероятно, откуда появились экземпляры.

+6
18 февр. '14 в 10:43
источник

Представьте, что вы пишете класс с serialVersionUID, создавайте его, затем сериализуете его в файл (с помощью ObjectOutputStream)

Затем вы изменяете класс.

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

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

+3
18 февр. '14 в 10:38
источник

Значение используется при сериализации объекта и де-сериализации объекта обратно в JVM.

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

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

Лучшей практикой является изменение serialVersionUID, каждый раз, когда у вас есть некоторые несовместимые изменения в классе.

+3
18 февр. '14 в 10:36
источник

Вы можете назначить любое значение long для serialVersionUID, но вы должны изменять его каждый раз, когда вы изменяете свой класс.

Второй выглядит как сгенерированный serialVersionUID, основанный на функциях текущей версии класса.

+2
18 февр. '14 в 10:31
источник

Важно подчеркнуть тот факт, что при реализации класса интерфейс Serializable делает ВСЕ поля не объявленными transient частью экспортированного API класса, объявлены ли эти поля private.

Другими словами, реализация Serializable:

  • прерывает инкапсуляцию. Если у класса есть шанс стать успешным, долгоживущим классом, тогда вы должны поддерживать сериализованную форму... навсегда.

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

  • может создавать проблемы безопасности для вашего класса и его приложения. Deserialization представляет собой способ создания объектов Java без конструктора, поэтому можно нарушать инварианты класса, предоставляя потоки байтов-изгоев в средство десериализации.

serialVerionUID следует рассматривать как свойство сериализованной формы. Он предназначен для передачи одной JVM независимо от того, существует ли разница между сериализованной формой экземпляра класса, которую он получает, и сериализованной формой того же класса, который был сделан (возможно) где-то еще.

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

TL;DR: вы не должны изменять UID, когда вам это нравится. Вы должны изменить его, если сериализованная форма класса изменится, чтобы версии программного обеспечения, использующие более старые версии вашего класса (с другой сериализованной формой), разбились вместо (возможно, молча), делая неправильную вещь, Не разрабатывая хорошую сериализованную форму, ваши классы затруднят (даже намного сложнее) обеспечение обратной совместимости для своих клиентов. В идеальном случае сериализованная форма для класса сохраняется на протяжении всей его эволюции (и поэтому ее UID никогда не меняется).

+2
24 янв. '15 в 23:57
источник

Посмотрите другие вопросы по метке или Задайте вопрос