24 Вопрос: Что такое serialVersionUID и почему я должен его использовать?

вопрос создан в Tue, Mar 17, 2015 12:00 AM

Eclipse выдает предупреждения, если отсутствует serialVersionUID.

  

Сериализуемый класс Foo не объявляет статический финал   Поле serialVersionUID типа long

Что такое serialVersionUID и почему это важно? Пожалуйста, покажите пример, где отсутствие serialVersionUID вызовет проблему.

    
2767
24 ответа                              24                         

Документы для java.io.Serializable , вероятно, примерно такое же хорошее объяснение, как вы получите:

  

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

ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
     

Если сериализуемый класс явно не объявляет serialVersionUID, то среда выполнения сериализации вычислит значение по умолчанию serialVersionUID для этого класса на основе различных аспектов класса, как описано в Спецификации сериализации объектов Java (TM). Однако настоятельно рекомендуется , чтобы все сериализуемые классы явно объявляли значения serialVersionUID, поскольку вычисление по умолчанию serialVersionUID очень чувствительно к деталям класса, которые могут различаться в зависимости от реализаций компилятора, и, следовательно, могут приводить к неожиданным InvalidClassExceptions во время десериализации. , Поэтому, чтобы гарантировать согласованное значение serialVersionUID в различных реализациях Java-компилятора, сериализуемый класс должен объявить явное значение serialVersionUID. Также настоятельно рекомендуется, чтобы в явных объявлениях serialVersionUID использовался частный модификатор, когда это возможно, поскольку такие объявления применяются только к немедленно объявленным полям класса serialVersionUID и не используются как унаследованные члены.

    
2111
2018-11-14 09: 45: 44Z
  1. Итак, по сути, вы говорите, что, если пользователь не понимает весь вышеупомянутый материал, он не должен беспокоиться о сериализации? Я полагаю, вы ответили "как?" вместо того, чтобы объяснять «почему?». Я, например, не понимаю, почему я должен беспокоиться о SerializableVersionUID.
    2009-01-01 07: 27: 10Z
  2. Причина во втором абзаце: если вы не укажете явным образом serialVersionUID, значение будет сгенерировано автоматически - но это хрупко, потому что это зависит от реализации компилятора.
    2009-01-01 20: 26: 06Z
  3. И почему Eclipse говорит, что мне нужно "private static final long serialVersionUID = 1L;" когда я расширяю класс Exception?
    2014-06-15 17: 12: 39Z
  4. @ JohnMerlino: Ну, я бы не ожидал, что он скажет, что вам нужен один - но это может быть предложение один, чтобы помочь вам правильно сериализовать исключения. Если вы не собираетесь их сериализовать, вам действительно не нужна константа.
    2014-06-15 18: 43: 23Z
    Ля>
  5. @ JohnMerlino, чтобы ответить на вопрос «почему»: исключение реализует Serializable и eclipse предупреждает, что вы не установили serialVersionUID, что было бы хорошей идеей (если вы не хотите сериализовать класс) чтобы избежать проблем, изложенных в посте JonSkeet.
    2014-10-08 11: 48: 52Z

Если вы сериализуете только потому, что вам нужно сериализовать ради реализации (кого волнует, если вы сериализуете для HTTPSession, например ... если он сохранен или нет, вам, вероятно, не важно, de-serializing62 объект формы ), тогда вы можете проигнорировать это.

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

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

    
442
2019-02-24 07: 17: 24Z
  1. Я бы сказал, что если вы не используете сериализацию для постоянного хранения, вы должны использовать @SuppressWarnings, а не добавлять значение. Он меньше загромождает класс и сохраняет работоспособность механизма serialVersionUID, чтобы защитить вас от несовместимых изменений.
    2011-04-24 10: 43: 24Z
  2. Я не вижу, как добавление одной строки (аннотация @SuppressWarnings) в отличие от другой строки (serializable id) «меньше загромождает класс». И если вы не используете сериализацию для постоянного хранения, почему бы вам просто не использовать «1»? В любом случае, вы не будете заботиться об автоматически сгенерированном идентификаторе.
    2011-04-25 17: 09: 46Z
  3. @ MetroidFan2002: Я думаю, что точка @ TomAnderson serialVersionUID, защищающая вас от несовместимых изменений, действительна. Использование @SuppressWarnings лучше документирует намерение, если вы не хотите использовать класс для постоянного хранения.
    2011-12-30 14: 32: 05Z
  4. "Вы должны увеличивать его, если текущая версия вашего класса не обратно совместима с его предыдущей версией:" Сначала вы должны изучить расширенную поддержку Serialization для управления версиями объектов, ( а) чтобы гарантировать, что класс действительно теперь несовместим с сериализацией, чего в спецификации довольно трудно достичь; (б) попробовать схему, такую ​​как пользовательские методы read /writeObject (), методы readResolve /writeReplace (), объявления serializableFields и т. д., чтобы убедиться, что поток остается совместимым. Изменение фактического serialVersionUID - это последнее средство, совет отчаяния.
    2012-12-12 00: 59: 01Z
  5. @ Инкремент EJP serialVersionUID появляется, когда первоначальный автор класса представил явно. Я бы сказал, сгенерированный jvm серийный идентификатор должен быть в порядке. это лучший ответ , который я видел при сериализации.
    2014-12-24 15: 39: 38Z

Я не могу упустить эту возможность, чтобы подключить книгу Джоша Блоха Эффективная Java (2-е издание). Глава 11 является необходимым ресурсом по сериализации Java.

Согласно Джошу, автоматически сгенерированный UID генерируется на основе имени класса, реализованных интерфейсов и всех открытыхи защищенные члены. Изменение любого из них любым способом изменит serialVersionUID. Таким образом, вам не нужно связываться с ними, только если вы уверены, что не более одной версии класса когда-либо будет сериализовано (либо между процессами, либо получено из хранилища в позже).

Если вы сейчас их игнорируете и позже обнаружите, что вам нужно каким-то образом изменить класс, но сохранить совместимость со старой версией класса, вы можете использовать инструмент serialver JDK для генерации serialVersionUID для класса old и явно установите его для нового класса. (В зависимости от ваших изменений вам может также потребоваться реализовать пользовательскую сериализацию, добавив методы writeObject и readObject - см. Serializable javadoc или вышеупомянутую главу 11.)

    
282
2015-10-29 13: 32: 35Z
  1. Таким образом, можно использовать SerializableVersionUID, если вас беспокоит совместимость со старыми версиями класса?
    2009-01-01 07: 28: 35Z
  2. Да, в случае если более новая версия изменит какой-либо открытый член на защищенный, SerializableVersionUID по умолчанию будет другим и вызовет InvalidClassExceptions.
    2012-01-13 19: 49: 38Z
  3. Имя класса, реализованные интерфейсы, все открытые и защищенные методы, ВСЕ переменные экземпляра.
    2013-03-01 04: 38: 29Z
  4. Стоит отметить, что Джошуа Блох советует, что для каждого сериализуемого класса стоит указать серийную версию uid. Цитата из главы 11: Независимо от того, какую сериализованную форму вы выберете, объявляйте явный UID последовательной версии в каждом сериализуемом классе, который вы пишете. Это исключает UID серийной версии в качестве потенциального источника несовместимости (элемент 74). Существует также небольшое преимущество в производительности. Если UID с последовательной версией не предоставлен, для его генерации во время выполнения требуются дорогостоящие вычисления.
    2014-07-08 13: 25: 35Z

Вы можете указать Eclipse игнорировать эти предупреждения serialVersionUID:

  

Окно > Настройки > Java > Компилятор > Ошибки /Предупреждения > Потенциальные проблемы программирования

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

  • Потенциальные проблемы программирования: возможное случайное логическое назначение
  • Потенциальные проблемы программирования: доступ с нулевым указателем
  • Ненужный код: локальная переменная никогда не читается
  • Ненужный код: избыточная нулевая проверка
  • Ненужный код: Ненужное приведение или 'instanceof'

и многое другое.

    
128
2008-11-13 01: 17: 00Z
  1. upvote, но только потому, что оригинальный постер ничего не сериализует. Если бы на плакате говорилось: «Я сериализирую эту штуку и ...», тогда вы получите вместо этого голос: P
    2008-11-13 01: 28: 31Z
  2. Верно - я предполагал, что спрашивающий просто не хочет, чтобы его предупреждали
    2008-11-13 02: 52: 08Z
  3. @ Gardner - > согласовано! Но спрашивающий также хочет знать, почему он не хочет, чтобы его предупреждали.
    2009-01-01 07: 29: 35Z
  4. Очевидно, что спрашивающий заботится о том, почему должен быть UID. Так что просто сказать ему, чтобы он проигнорировал предупреждение, следует опровергнуть.
    2017-04-18 03: 31: 38Z

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

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

Встроенный механизм десериализации (in.defaultReadObject()) будет отказываться от десериализации старых версий данных. Но если вы хотите, вы можете определить свой собственный readObject () -функция, которая может читать старые данные. Этот пользовательский код может затем проверить serialVersionUID, чтобы узнать, в какой версии находятся данные, и решить, как десериализовать их. Этот метод управления версиями полезен, если вы храните сериализованные данные, которые сохраняются в нескольких версиях вашего кода.

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

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

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

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

Но есть и обратная сторона автоматически генерируемой стратегии id. А именно, что сгенерированные идентификаторы для одного и того же класса могут отличаться в разных компиляторах (как упоминалось выше Jon Skeet). Поэтому, если вы передаете сериализованные данные между кодом, скомпилированным с разными компиляторами, рекомендуется в любом случае поддерживать идентификаторы вручную.

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

    
103
2012-10-03 06: 20: 58Z
  1. Добавление или удаление непереходных полей не делает сериализацию несовместимой с классом. Таким образом, нет никаких оснований для «поднятия» таких изменений.
    2014-02-07 01: 05: 33Z
  2. @ EJP: А? Добавление данных определенно меняет данные сериализации в моем мире.
    2014-02-07 19: 12: 41Z
  3. @ AlexanderTorstling Прочитайте, что я написал. Я не говорил, что это не «меняет данные сериализации». Я сказал, что это не делает сериализацию несовместимой с сериализацией. Это не одно и то же. Вам необходимо прочитать главу «Управление версиями» в Спецификации сериализации объектов.
    2014-05-20 21: 27: 51Z
  4. @ EJP: я понимаю, что добавление непереходного поля не обязательно означает, что вы делаете сериализацию несовместимой с классом, но это структурное изменение, которое изменяет сериализованные данные ивы обычно хотите изменить версию при этом, если вы не обращаетесь с обратной совместимостью, что я также объяснил позже в посте. Какова ваша точка зрения?
    2014-05-21 06: 42: 17Z
  5. Моя точка зрения остается именно тем, что я сказал. Добавление или удаление непереходных полей не делает класс несовместимым с сериализацией. Поэтому вам не нужно увеличивать serialVersionUID каждый раз, когда вы делаете это.
    2015-05-04 11: 16: 27Z
  

Что такое serialVersionUID и почему я должен его использовать?

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

Указание одного дает больше контроля, хотя JVM генерирует его, если вы не укажете. Сгенерированное значение может отличаться для разных компиляторов. Кроме того, иногда вы просто хотите по какой-то причине запретить десериализацию старых сериализованных объектов [backward incompatibility], и в этом случае вам просто нужно изменить serialVersionUID.

javadocs для Serializable скажем :

  

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

Поэтому вы должны объявить serialVersionUID, поскольку он дает нам больше контроля .

В этой статье есть несколько полезных моментов по этой теме. р>     

67
2018-07-08 07: 03: 56Z
  1. @ Vinothbabu, но serialVersionUID является статическим, поэтому статические переменные нельзя сериализовать. тогда почему jvm проверит версию, не зная, какая версия десериализованного объекта
    2014-06-16 11: 06: 45Z
  2. Единственное, что не упомянуто в этом ответе, это то, что вы можете вызвать непредвиденные последствия, включив вслепую serialVersionUID, не зная, почему. Комментарий Тома Андерсона к ответу MetroidFan2002 касается этого: «Я бы сказал, что если вы не используете сериализацию для постоянного хранения, вам следует использовать @SuppressWarnings вместо добавления значения. Это меньше загромождает класс и сохраняет способность Механизм serialVersionUID для защиты от несовместимых изменений. "
    2014-06-17 16: 30: 51Z
  3. serialVersionUID не является не «уникальным идентификатором для каждого класса». Полное имя класса таково. Это индикатор версии .
    2015-06-09 04: 17: 18Z

В первоначальном вопросе спрашивалось «почему это важно» и «пример», где этот Serial Version ID будет полезен. Ну, я нашел один.

Допустим, вы создали класс Car, создаете его экземпляр и записываете его в поток объектов. Расплющенный объект автомобиля некоторое время находится в файловой системе. Между тем, если класс Car изменяется путем добавления нового поля. Позже, когда вы попытаетесь прочитать (т.е. десериализовать) уплощенный объект Car, вы получите java.io.InvalidClassException - поскольку всем сериализуемым классам автоматически присваивается уникальный идентификатор. Это исключение выдается, когда идентификатор класса не равен идентификатору сплющенного объекта. Если вы действительно думаете об этом, исключение выдается из-за добавления нового поля. Вы можете избежать этого исключения, управляя версионированием самостоятельно с помощью declaring явный serialVersionUID. Существует также небольшое преимущество в производительности, поскольку вы явно декларируете serialVersionUID (так как вычислять не нужно). Поэтому рекомендуется добавлять свой собственный serialVersionUID в свои классы Serializable, как только вы создадите их, как показано ниже:

public class Car {
    static final long serialVersionUID = 1L; //assign a long value
}
    
51
2019-01-14 14: 56: 35Z
  1. И каждому UID следует назначать случайное длинное число, а не 1L.
    2017-10-27 01: 34: 29Z
  2. @ abbas "Нужно" сделать это, почему? Пожалуйста, объясните, в чем разница.
    2017-11-25 08: 58: 18Z
  3. Как следует из названия, он представляет версию класса, который использовался для сериализации объекта. Если вы назначаете ему один и тот же номер каждый раз, вы не сможете найти подходящий класс для десериализации. Поэтому, когда вы вносите изменения в класс, лучше тоже изменить версию.
    2017-11-27 00: 39: 02Z
  4. @ abbas, это намерение не противоречит использованию увеличивающихся натуральных чисел от 1 и т. д.
    2017-12-14 18: 21: 39Z
  5. @ BillK, я думал, что проверка сериализации связана с парой classname и serialVersionUID. Так что разные схемы нумерации разных классов и библиотек никак не могут мешать. Или вы подразумевали библиотеки, генерирующие код?
    2018-01-26 10: 26: 44Z

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

    
34
2014-07-09 18: 46: 25Z
  1. Если вы не собираетесь сериализовывать объекты, почему они сериализуются?
    2008-11-13 05: 34: 51Z
  2. @ erickson - родительский класс может быть сериализуемым, скажем, ArrayList, но вы хотите, чтобы ваш собственный объект (скажем, список измененных массивов) использовал его в качестве базы, но никогда не будет сериализовать коллекцию, которую вы создаете.
    2009-03-30 14: 12: 39Z
  3. Он не упоминается нигде в спецификации языка Java. Это упомянуто в спецификации управления версиями объекта.
    2014-02-07 01: 10: 04Z
  4. 2014-11-03 04: 12: 45Z

Если вы получаете это предупреждение о классе, о котором вы даже не задумываетесь о сериализации, и что вы не объявили себя implements Serializable, это часто происходит потому, что вы унаследовали от суперкласса, который реализует Serializable. Часто тогда было бы лучше делегировать такой объект вместо использования наследования.

Итак, вместо

public class MyExample extends ArrayList<String> {

    public MyExample() {
        super();
    }
    ...
}

делать

public class MyExample {
    private List<String> myList;

    public MyExample() {
         this.myList = new ArrayList<String>();
    }
    ...
}

и в соответствующих методах вызовите myList.foo() вместо this.foo() (или super.foo()). (Это подходит не во всех случаях, но все же довольно часто.)

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

Один из случаев, когда предупреждение (или serialVersionUID) является неизбежным, - это когда вы расширяетесь из AbstractAction, обычно в анонимном классе, только добавляя actionPerformed-метод. Я думаю, что в этом случае не должно быть предупреждения (поскольку вы в любом случае не можете надежно сериализовать и десериализовать такие анонимные классы в любом случае в разных версиях вашего класса), но я не уверен, как компилятор мог это распознать. р>     

33
2011-02-03 00: 32: 03Z
  1. Я думаю, что вы правы, так как композиция по сравнению с наследованием имеет больше смысла, особенно когда вы обсуждаете такие классы, как ArrayList. Тем не менее, многие фреймворки требуют, чтобы люди выходили из абстрактных суперклассов, которые можно сериализировать (например, класс ActionForm в Struts 1.2 или Saxon ExtensionFunctionDefinition), и в этом случае это решение невозможно. Я думаю, что вы правы, было бы неплохо, если бы предупреждение было проигнорировано в некоторых случаях (например, если вы выходили из абстрактного сериализуемого класса)
    2011-12-07 15: 20: 48Z
  2. Конечно, если вы добавляете класс в качестве члена, а не наследуете его, вам нужно будет написать метод-обертку для КАЖДОГО метода класса-члена, который вы хотели бы использование, которое сделало бы его невозможным в большом количестве ситуаций ... если только у java нет функции, аналогичной функции perl __AUTOLOAD, о которой я не знаю.
    2012-08-19 22: 15: 36Z
  3. @ M_M: когда вы делегируете множество методов для вашего обернутого объекта, конечно, было бы нецелесообразно использовать делегирование. Но я полагаю, что этот случай является признаком ошибки проектирования - пользователям вашего класса (например, «MainGui») не нужно вызывать множество методов обернутого объекта (например, JFrame).
    2012-08-20 08: 09: 56Z
  4. Что мне не нравится в делегировании, так это необходимость хранить ссылку на делегата. И каждая ссылка означает больше памяти. Поправьте меня если я ошибаюсь. Если мне нужен CustomizedArrayList из 100 объектов, это не будет иметь большого значения, но если мне понадобятся сотни CustomizdeArrayList для нескольких объектов, использование памяти значительно возрастет.
    2014-11-29 07: 14: 46Z
  5. Throwable является сериализуемым, и только Throwable является бросаемым, поэтому невозможно определить исключение, которое не сериализуемо. Делегирование невозможно.
    2017-04-13 02: 59: 08Z

Чтобы понять значение поля serialVersionUID, необходимо понять, как работает сериализация /десериализация.

Когда сериализуемый объект класса сериализуется, Java Runtime связывает серийный номер версии (называемый serialVersionUID) с этим сериализованным объектом. Во время десериализации этого сериализованного объекта среда выполнения Java сопоставляет serialVersionUID сериализованного объекта с serialVersionUID класса. Если оба значения равны, то только он продолжается с дальнейшим процессом десериализации, иначе выдает InvalidClassException.

Таким образом, мы делаем вывод, что для успешного выполнения процесса сериализации /десериализации serialVersionUID сериализованного объекта должен быть эквивалентен serialVersionUID класса. В случае, если программист явно указывает значение serialVersionUID в программе, то это же значение будет связано с сериализованным объектом и классом, независимо от платформы сериализации и десериализации (например, сериализация может быть выполнена на платформе, такой как windows, с использованием sun или MS JVM и десериализация могут быть на разных платформах Linux с использованием Zing JVM).

Но в случае, если serialVersionUID не указан программистом tПри выполнении сериализации \десериализации любого объекта среда выполнения Java использует собственный алгоритм для его вычисления. Этот алгоритм вычисления serialVersionUID варьируется от одного JRE к другому. Также возможно, что среда, в которой объект сериализуется, использует одну JRE (например, SUN JVM), а среда, в которой происходит десериализация, использует Linux Jvm (zing). В таких случаях serialVersionUID, связанный с сериализованным объектом, будет отличаться от serialVersionUID класса, рассчитанного в среде десериализации. В свою очередь десериализация не будет успешной. Поэтому, чтобы избежать таких ситуаций /проблем, программист должен всегда указывать serialVersionUID класса Serializable.

    
22
2014-05-20 21: 34: 52Z
  1. Алгоритм не меняется, но он немного не указан.
    2014-05-20 21: 35: 10Z

Сначала мне нужно объяснить сериализацию.
Сериализация позволяет преобразовать объект в поток для отправки этого объекта по сети, ИЛИ сохранить в файл ИЛИ сохранить в БД для использования в письмах.

Существуют некоторые правила для сериализации .

  • Объект сериализуем, только если его класс или его суперкласс реализуют интерфейс Serializable

  • Объект является сериализуемым (сам реализует интерфейс Serializable), даже если его суперкласс - нет. Однако первый суперкласс в иерархии сериализуемого класса, который не реализует интерфейс Serializable, ДОЛЖЕН иметь конструктор без аргументов. Если это нарушено, readObject () создаст исключение java.io.InvalidClassException во время выполнения

  • Все примитивные типы являются сериализуемыми.

  • Переходные поля (с модификатором переходного процесса) НЕ сериализуются (т.е. не сохраняются и не восстанавливаются). Класс, который реализует Serializable, должен отмечать переходные поля классов, которые не поддерживают сериализацию (например, файловый поток).

  • Статические поля (со статическим модификатором) не сериализуются.

Когда объект сериализован, JAVA Runtime связывает серийный номер версии, который называется serialVersionID.

Где нам нужен serialVersionID: Во время десериализации, чтобы убедиться, что отправитель и получатель совместимы с сериализацией. Если получатель загрузил класс с другим serialVersionID, то десериализация закончится с InvalidClassCastException .
 Сериализуемый класс может объявить свой собственный serialVersionUID в явном виде, объявив поле с именем «serialVersionUID», которое должно быть статическим, конечным и иметь тип long:.

Давайте попробуем это на примере.

import java.io.Serializable;    
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private String empname;
private byte empage;

public String getEmpName() {
    return name;
}
public void setEmpName(String empname) {
    this.empname = empname;
}
public byte getEmpAge() {
    return empage;
}
public void setEmpAge(byte empage) {
    this.empage = empage;
}

public String whoIsThis() {
    StringBuffer employee = new StringBuffer();
    employee.append(getEmpName()).append(" is ).append(getEmpAge()).append("
years old  "));
    return employee.toString();
}
}

Создать объект сериализации

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class Writer {
public static void main(String[] args) throws IOException {
    Employee employee = new Employee();
    employee.setEmpName("Jagdish");
    employee.setEmpAge((byte) 30);

    FileOutputStream fout = new 
FileOutputStream("/users/Jagdish.vala/employee.obj");
    ObjectOutputStream oos = new ObjectOutputStream(fout);
    oos.writeObject(employee);
    oos.close();
    System.out.println("Process complete");
}
}

Десериализация объекта

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class Reader {
public static void main(String[] args) throws ClassNotFoundException, 
IOException {
    Employee employee = new Employee();
    FileInputStream fin = new 
    FileInputStream("/users/Jagdish.vala/employee.obj");
    ObjectInputStream ois = new ObjectInputStream(fin);
    employee = (Employee) ois.readObject();
    ois.close();
    System.out.println(employee.whoIsThis());
 }
}    

ПРИМЕЧАНИЕ. Теперь измените serialVersionUID класса Employee и сохраните:

private static final long serialVersionUID = 4L;

И выполните класс Reader. Не выполнять класс Writer, и вы получите исключение.

Exception in thread "main" java.io.InvalidClassException: 
com.jagdish.vala.java.serialVersion.Employee; local class incompatible: 
stream classdesc serialVersionUID = 1, local class serialVersionUID = 4
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1623)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at com.krishantha.sample.java.serialVersion.Reader.main(Reader.java:14)
    
19
2019-05-03 02: 38: 13Z

Не беспокойтесь, расчет по умолчанию действительно хорош и достаточен для 99,9999% случаев. И если у вас возникнут проблемы, вы можете - как уже говорилось - вводить UID как необходимость (что весьма маловероятно)

    
18
2012-04-29 15: 59: 41Z
  1. Мусор. Это достаточно для случая, когда класс не изменился. У вас нет доказательств в поддержку «99,9999%».
    2018-03-22 10: 30: 44Z

Как в примере, где отсутствующий serialVersionUID может вызвать проблему:

Яработает над этим приложением Java EE, которое состоит из веб-модуля, использующего модуль EJB. Веб-модуль вызывает модуль EJB удаленно и передает в качестве аргумента POJO, который реализует Serializable.

Этот класс POJO's был упакован внутри EJB-файла и внутри его собственного JAR-файла в WEB-INF /lib веб-модуля. На самом деле это один и тот же класс, но когда я упаковываю модуль EJB, я распаковываю этот jar-файл POJO, чтобы упаковать его вместе с модулем EJB.

Вызов EJB не удался с приведенным ниже исключением, потому что я не объявил его serialVersionUID:

Caused by: java.io.IOException: Mismatched serialization UIDs : Source
 (Rep.
 IDRMI:com.hordine.pedra.softbudget.domain.Budget:5CF7CE11E6810A36:04A3FEBED5DA4588)
 = 04A3FEBED5DA4588 whereas Target (Rep. ID RMI:com.hordine.pedra.softbudget.domain.Budget:7AF5ED7A7CFDFF31:6227F23FA74A9A52)
 = 6227F23FA74A9A52
    
18
2013-12-19 18: 15: 18Z

Обычно я использую serialVersionUID в одном контексте: когда я знаю, что он покидает контекст Java VM.

Я знаю это, когда буду использовать ObjectInputStream и ObjectOutputStream для своего приложения или если я знаю, что библиотека /инфраструктура, которую я использую, будет ее использовать. SerialVersionID гарантирует, что разные виртуальные машины Java разных версий или поставщиков будут правильно взаимодействовать или если они сохранены и получены вне виртуальной машины, например, HttpSession, данные сеанса могут остаться даже во время перезапуска и обновления сервера приложений.

Для всех остальных случаев я использую

@SuppressWarnings("serial")

, так как большую часть времени достаточно по умолчанию serialVersionUID. Это включает Exception, HttpServlet.

    
15
2014-03-04 16: 17: 48Z
  1. Он не включает HttpServlet в контейнеры, где они могут быть заменены, или исключение в RMI, например.
    2014-05-20 21: 36: 16Z

Данные поля представляют некоторую информацию, хранящуюся в классе. Класс реализует интерфейс Serializable, поэтому eclipse автоматически предлагает объявить поле serialVersionUID. Давайте начнем со значения 1, установленного там.

Если вы не хотите, чтобы появилось это предупреждение, используйте это:

@SuppressWarnings("serial")
    
14
2013-03-13 14: 54: 36Z

SerialVersionUID используется для контроля версий объекта. вы также можете указать serialVersionUID в вашем файле класса. Следствием отсутствия указания serialVersionUID является то, что при добавлении или изменении какого-либо поля в классе уже сериализованный класс не сможет восстановиться, поскольку serialVersionUID, сгенерированный для нового класса и для старого сериализованного объекта, будет отличаться. Процесс сериализации Java использует правильный serialVersionUID для восстановления состояния сериализованного объекта и создает исключение java.io.InvalidClassException в случае несовпадения serialVersionUID

Подробнее: http://javarevisited.blogspot.com/2011/04 /топ-10-Java-сериализации-interview.html # ixzz3VQxnpOPZ

    
11
2015-03-25 21: 08: 11Z

Было бы неплохо, если бы CheckStyle мог проверить, что serialVersionUID в классе, который реализует Serializable, имеет хорошее значение, то есть соответствует тому, что будет генерировать генератор идентификатора последовательной версии. Если у вас есть проект с большим количеством сериализуемых DTO, например, не забудьте удалить существующий serialVersionUID и восстановить его, это боль, и в настоящее время единственный (который я знаю) способ проверить это - восстановить для каждого класса и сравнить с Старый. Это очень очень больно.

    
10
2008-12-03 14: 44: 33Z
  1. Если вы всегда устанавливаете serialVersionUID равным значению, которое будет генерировать генератор, вам это вообще не нужно. В конце концов, смысл его существования - оставаться неизменным после изменений, когда класс все еще совместим.
    2011-02-20 02: 04: 13Z
  2. Причина в том, что разные компиляторы имеют одинаковое значение для одного и того же класса. Как объяснено в javadocs (также ответил выше), сгенерированная версия является хрупкой и может варьироваться, даже если класс должным образом десериализуем. Если вы каждый раз запускаете этот тест на одном и том же компиляторе, он должен быть безопасным. Бог поможет вам, если вы обновите JDK, и появится новое правило, даже если ваш код не изменился.
    2011-08-09 08: 29: 23Z
  3. Нет необходимости совпадать с тем, что выдаст serialver. -1
    2014-02-07 01: 10: 45Z
  4. В общем случае это вообще не требуется. В случае @ AndrewBacker потребовалось бы два разных компилятора в одном и том же файле .java, при этом обе версии файлов .class связывались бы друг с другом - большую часть времени вы просто создаете класс и распространяете его. Если это так, то отсутствие SUID будет работать нормально.
    2018-01-25 21: 06: 35Z
  5. Люди, которые действительно используют сериализацию для целей хранения /извлечения, обычно устанавливают serialVersionUID равным 1. Если более новая версия класса несовместима, но все же требует возможности для обработки старых данных вы увеличиваете номер версии и добавляете специальный код для работы со старыми форматами. Я плачу каждый раз, когда вижу serialVersionUID больше 1 цифры, либо потому, что это было случайное число (бесполезное), либо потому, что класс, очевидно, должен иметь дело с более чем 10 различными версиями.
    2018-02-10 11: 11: 51Z

Зачем использовать SerialVersionUID внутри класса Serializable в Java?

В течение serialization среда выполнения Java создает номер версии для класса, чтобы впоследствии можно было десериализовать его. Этот номер версии известен как SerialVersionUID в Java.

SerialVersionUID используется для версии сериализованных данных. Десериализовать класс можно только в том случае, если его SerialVersionUID совпадает с сериализованным экземпляром. Когда мы не объявляем SerialVersionUID в нашем классе, среда выполнения Java генерирует его для нас, но это не рекомендуется. Рекомендуется объявлять SerialVersionUID как переменную private static final long, чтобы избежать механизма по умолчанию.

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

см. также Зачем использовать SerialVersionUID внутри класса Serializable в Java

Код: javassist.SerialVersionUID

    
9
2017-03-07 05: 48: 02Z

Если вы хотите изменить огромное количество классов, для которых не был установлен serialVersionUID, в первую очередь, при сохранении совместимости со старыми классами, инструменты, такие как IntelliJ Idea, Eclipse, не дотягивают, так как они генерируют случайные числа и не работают на куча файлов за один раз. Я придумаю следующий скрипт bash (извините заПользователи Windows, рассмотрите возможность покупки Mac или перехода на Linux), чтобы легко исправить проблему serialVersionUID:

base_dir=$(pwd)                                                                  
src_dir=$base_dir/src/main/java                                                  
ic_api_cp=$base_dir/target/classes                                               

while read f                                                                     
do                                                                               
    clazz=${f//\//.}                                                             
    clazz=${clazz/%.java/}                                                       
    seruidstr=$(serialver -classpath $ic_api_cp $clazz | cut -d ':' -f 2 | sed -e 's/^\s\+//')
    perl -ni.bak -e "print $_; printf qq{%s\n}, q{    private $seruidstr} if /public class/" $src_dir/$f
done

вы сохраняете этот скрипт, скажем add_serialVersionUID.sh вам ~ /bin. Затем вы запускаете его в корневом каталоге вашего проекта Maven или Gradle, например:

add_serialVersionUID.sh < myJavaToAmend.lst

В этом .lst содержится список файлов Java для добавления serialVersionUID в следующем формате:

com/abc/ic/api/model/domain/item/BizOrderTransDO.java
com/abc/ic/api/model/domain/item/CardPassFeature.java
com/abc/ic/api/model/domain/item/CategoryFeature.java
com/abc/ic/api/model/domain/item/GoodsFeature.java
com/abc/ic/api/model/domain/item/ItemFeature.java
com/abc/ic/api/model/domain/item/ItemPicUrls.java
com/abc/ic/api/model/domain/item/ItemSkuDO.java
com/abc/ic/api/model/domain/serve/ServeCategoryFeature.java
com/abc/ic/api/model/domain/serve/ServeFeature.java
com/abc/ic/api/model/param/depot/DepotItemDTO.java
com/abc/ic/api/model/param/depot/DepotItemQueryDTO.java
com/abc/ic/api/model/param/depot/InDepotDTO.java
com/abc/ic/api/model/param/depot/OutDepotDTO.java

Этот скрипт использует инструмент JDK serialVer под капотом. Поэтому убедитесь, что ваш $JAVA_HOME /bin находится в PATH.

    
7
2015-06-27 12: 36: 07Z
  1. Дает мне идею: всегда регенерируйте uid серийной версии с помощью инструмента, подобного этому, никогда не делайте вручную, прежде чем делать релиз - таким образом, вы не забудете сделать перейдите к классу, чья серийная версия uid должна была измениться из-за фактического несовместимого изменения. Отслеживать это вручную очень сложно.
    2016-03-17 18: 05: 45Z

Этот вопрос очень хорошо задокументирован в книге «Эффективная Java» Джошуа Блоха. Очень хорошая книга, которую нужно прочитать. Я изложу некоторые из причин ниже:

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

Если класс сериализуем, вы также можете явно объявить свой собственный serialVersionUID, объявив поле с именем "serialVersionUID", которое должно быть статическим, конечным и типа long. Большинство IDE, таких как Eclipse, помогают вам генерировать эту длинную строку.

    
6
2015-08-03 19: 41: 31Z

Каждый раз, когда объект сериализуется, на объекте ставится отметка с идентификатором версии для класса объекта. Этот идентификатор называется serialVersionUID и он рассчитывается на основе информации о структуре класса. Предположим, вы создали класс Employee и у него есть идентификатор версии # 333 (назначенный JVM). Теперь, когда вы будете сериализовать объект этого класса (предположим, объект Employee), JVM назначит ему UID как # 333.

Рассмотрим ситуацию - в будущем вам нужно отредактировать или изменить свой класс, и в этом случае, когда вы его измените, JVM назначит ему новый UID (предположим, # 444). Теперь, когда вы попытаетесь десериализовать объект employee, JVM сравнит идентификатор версии сериализованного объекта (объекта Employee) (# 333) с идентификатором класса i.e # 444 (поскольку он был изменен). При сравнении JVM обнаружит, что обе версии UID различаются, и, следовательно, десериализация не удастся. Следовательно, если serialVersionID для каждого класса определяется самим программистом. Это будет то же самое, даже если класс будет развиваться в будущем, и, следовательно, JVM всегда обнаружит, что класс совместим с сериализованным объектом, даже если этот класс изменен. Для получения дополнительной информации вы можете обратиться к главе 14 HEAD FIRST JAVA.

    
6
2017-05-23 12: 34: 45Z
  1. Каждый раз, когда class объекта сериализуется, передается serialVersionUID. Не отправляется с каждым объектом.
    2017-11-25 09: 00: 06Z

Простое объяснение:

  1. Вы сериализуете данные?

    Сериализация - это запись данных класса в файл /поток /и т. д. Десериализация читает эти данные обратно в класс.

  2. Собираетесь ли вы пойти в производство?

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

  3. Это первая версия?

    Если это так, установите serialVersionUID=1L.

  4. Это вторая, третья и т. д. версия продукта?

    Теперь вам нужно побеспокоиться о serialVersionUID и рассмотреть его более подробно.

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

    
2
2019-04-12 13: 44: 29Z

Короче говоря, это поле используется для проверки правильности десериализации сериализованных данных. Сериализация и десериализация часто выполняются разными копиями программы - например, сервер преобразует объект в строку, а клиент преобразует полученную строку в объект. Это поле говорит о том, что оба оперируют одинаковыми представлениями о том, что это за объект. Это поле помогает, когда:

  • у вас есть много разных копий вашей программы в разных местах (например, 1 сервер и 100 клиентов). Если вы измените свой объект, измените свой номер версии и забудете обновить один из этих клиентов, он будет знать, что он не способен к десериализации

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

Когда это важно?

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

Менее очевидно - при десериализации объекта поля, которые не представлены в строке, будут сохранены как NULL. Если вы удалили поле из вашего объекта, более старые версии будут сохранять это поле как всегда-NULL, что может привести к неправильному поведению, если более старые версии полагаются на данные в этом поле (в любом случае вы создали его для чего-то, а не просто для удовольствия :-)) р>

Наименее очевидно - иногда вы меняете идею, которую вы вкладываете в значение некоторого поля. Например, когда вам 12 лет, вы подразумеваете «велосипед» под словом «велосипед», но когда вам 18 лет, вы имеете в виду «мотоцикл» - если ваши друзья пригласят вас на «поездку на велосипеде по городу», и вы будете единственным, кто Приехал на велосипеде, вы поймете, как важно сохранять одинаковое значение в разных областях: -)

    
0
2019-04-15 16: 55: 03Z

Во-первых, чтобы ответить на ваш вопрос, когда мы не объявляем SerialVersionUID в нашем классе, среда выполнения Java генерирует его для нас, но этот процесс чувствителен ко многим метаданным класса, включая количество полей, тип полей, модификатор доступа к полям. интерфейс реализован классом и т. д. Поэтому рекомендуется объявить его самостоятельно, и Eclipse предупреждает вас об этом.

Сериализация: Мы часто работаем с важными объектами, чье состояние (данные в переменных объекта) настолько важно, что мы не можем рискнуть потерять его из-за сбоев питания /системы (или) сбоев сети в случае отправки состояния объекта на другую машину. Решение этой проблемы называется «Постоянство», что просто означает сохранение (хранение /сохранение) данных. Сериализация является одним из многих других способов достижения постоянства (путем сохранения данных на диск /в память). При сохранении состояния объекта важно создать идентичность для объекта, чтобы иметь возможность правильно прочитать его обратно (десериализация). Этот уникальный идентификатор ID является SerialVersionUID.

    
0
2019-04-29 05: 06: 22Z
источник размещен Вот