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

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

The serializable class Foo does not declare a static final serialVersionUID field of type long

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

Найдите полезный опыт использования serialversionUID; dzone.com/articles/what-is-serialversionuid

ceyun 04.11.2019 14:28
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
3 136
1
970 365
26
Перейти к ответу Данный вопрос помечен как решенный

Ответы 26

Ответ принят как подходящий

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

The serialization runtime associates with each serializable class a version number, called a serialVersionUID, which is used during deserialization to verify that the sender and receiver of a serialized object have loaded classes for that object that are compatible with respect to serialization. If the receiver has loaded a class for the object that has a different serialVersionUID than that of the corresponding sender's class, then deserialization will result in an InvalidClassException. A serializable class can declare its own serialVersionUID explicitly by declaring a field named serialVersionUID that must be static, final, and of type long:

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

If a serializable class does not explicitly declare a serialVersionUID, then the serialization runtime will calculate a default serialVersionUID value for that class based on various aspects of the class, as described in the Java(TM) Object Serialization Specification. However, it is strongly recommended that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected InvalidClassExceptions during deserialization. Therefore, to guarantee a consistent serialVersionUID value across different java compiler implementations, a serializable class must declare an explicit serialVersionUID value. It is also strongly advised that explicit serialVersionUID declarations use the private modifier where possible, since such declarations apply only to the immediately declaring class — serialVersionUID fields are not useful as inherited members.

Итак, по сути, вы говорите, что если пользователь не понимает всего вышеупомянутого материала, он может не беспокоиться о сериализации? Я полагаю, вы ответили на вопрос "как?" вместо того, чтобы объяснять «почему?». Я, например, не понимаю, почему я вообще беспокоюсь о SerializableVersionUID.

Ziggy 01.01.2009 10:27

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

Jon Skeet 01.01.2009 23:26

И почему Eclipse говорит, что мне нужен "private static final long serialVersionUID = 1L;" когда я расширяю класс Exception?

JohnMerlino 15.06.2014 21:12

@JohnMerlino: Ну, я бы не ожидал, что он скажет, что вы необходимость, но это может быть предлагая, чтобы помочь вам правильно сериализовать исключения. Если вы не собираетесь сериализовать их, вам действительно не нужна константа.

Jon Skeet 15.06.2014 22:43

@JohnMerlino, чтобы ответить на ваш вопрос, почему: Exception реализует Сериализуемый, а eclipse предупреждает, что вы не установили serialVersionUID, что было бы хорошей идеей (если вы не хотите сериализовать класс), чтобы избежать проблем, которые сообщение JonSkeet очертания.

zpon 08.10.2014 15:48

@JonSkeet Значит ли это, что помимо идентичного определения класса я должен использовать точно такой же номер версии? Как я мог это узнать, если у меня нет возможности взглянуть на исходный код сериализованного класса?

smwikipedia 22.12.2014 15:55

@smwikipedia: Для десериализации данных? да. Однако было бы странно десериализовать данные для класса, для которого у вас не было источника. Двоичная сериализация не должна (IMO) использоваться в качестве общедоступного протокола общего назначения.

Jon Skeet 22.12.2014 15:56

@Ziggy If ".. поскольку вычисление serialVersionUID по умолчанию очень чувствительно к деталям класса, которые могут различаться в зависимости от реализаций компилятора и, таким образом, могут привести к неожиданным InvalidClassExceptions во время десериализации." не отвечает Почему тогда я боюсь, придется попросить вас определить почему: D

amertkara 10.07.2015 19:17

@JonSkeet В своем ответе вы упомянули, что «поскольку такие объявления применяются только к немедленно объявленному классу - поля serialVersionUID не используются в качестве унаследованных членов». не могли бы вы объяснить это? Поскольку, насколько я знаю, если родительский класс сериализуется, дочерний класс также сериализуется по умолчанию, поэтому нам нужно также объявить SerialVersionUID для дочернего элемента?

notescrew 04.12.2015 12:03

@proudandhonour: Да, вы должны это сделать.

Jon Skeet 04.12.2015 12:04

@JonSkeet Если я сделаю его защищенным, то что? Не будет ли это унаследовано в дочернем классе?

notescrew 04.12.2015 12:06

@proudandhonour: Я точно не знаю, что происходит в этих случаях, но почему бы просто не объявить это отдельно в каждом классе, как следует из документации?

Jon Skeet 04.12.2015 12:12

Всего два цента, это проблема Spark и других API-интерфейсов распараллеливания, которые зависят от сериализации классов Java в кластере.

JimLohse 20.12.2015 20:17

@JonSkeet, кто генерирует UID по умолчанию? JVM или компилятор / JDK?

Asif Mushtaq 28.06.2016 22:29

@UnKnown: среда выполнения сериализации - это время выполнения.

Jon Skeet 28.06.2016 22:37

Итак, если я правильно понимаю, указывать uid вручную небезопасно, чем позволять среде выполнения генерировать его. Потому что рано или поздно кто-то его забудет обновить ....

user1050755 11.06.2017 22:36

@ user1050755: В принципе, у каждого есть свои плюсы и минусы.

Jon Skeet 12.06.2017 00:29

Я не вижу никаких минусов против того, чтобы среда выполнения могла использовать "подпись" класса. Кажется, это идеальное решение для меня.

user1050755 12.06.2017 04:45

@ user1050755: Итак, вы счастливы, что изменение вашего компилятора, даже если оно не изменит никаких деталей самих полей, может сделать любые сохраненные данные нечитаемыми? Или добавление общедоступного статического метода, который действительно не должен изменять детали сериализации? Раньше я был укушен подобными вещами, поэтому это явный "недостаток". Возможно, если бы алгоритм был разработан лучше, все было бы хорошо, но с тем, как он спроектирован является, это плохие новости.

Jon Skeet 12.06.2017 08:47

Совет: если вы забыли добавить serialVersionUIDfield и хотите изменить класс, не затрагивая его, вы можете проверить его значение на немодифицированном и установить его для этого класса после того, как вы его изменили, используя этот вызов ( найдено по адресу: stackoverflow.com/a/26822688/878126): long serialVersionUID = ObjectStreamClass.lookup(YourClass.class).getSerialVersionUI‌​D();

android developer 04.06.2018 11:33

Большая часть этого вращается вокруг сериализации и того, почему ее, вероятно, НЕ следует использовать в качестве беспроводного протокола или постоянно сохранять и извлекать через десериализацию. Он эффективно создает реализацию «равных» на уровне класса и без каких-либо разумных методов для JVM и бесчисленных приложений / классов, созданных любым количеством разработчиков, чтобы сделать это согласованным / уникальным для данного класса ... немедленно создает нюансированную ошибку для младших разработчиков, если они сохранят класс как сериализованные данные, а затем позволят компилятору попытаться отсортировать версию класса во время десериализации.

Darrell Teague 09.07.2018 20:44

Итак, что произойдет, если я обновлю свой класс, но не обновлю serialVersionUIDfield?

bpoiss 19.08.2019 15:33

@bpoiss: Затем он попытается десериализовать старые данные с помощью нового класса и либо вызовет ошибки, либо фактически повредит данные, в зависимости от точного изменения.

Jon Skeet 19.08.2019 15:37

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

Если вы не собираетесь сериализовать объекты, почему они сериализуемы?

erickson 13.11.2008 08:34

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

MetroidFan2002 30.03.2009 18:12

Это нигде не упоминается в Спецификации языка Java. Это упоминается в Спецификации управления версиями объектов.

user207421 07.02.2014 05:10

Вот ссылка на Java 8 Спецификация управления версиями объектов.

Basil Bourque 03.11.2014 07:12

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

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

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

Итак, можно было бы побеспокоиться о SerializableVersionUID, если бы вы беспокоились о совместимости со старыми версиями класса?

Ziggy 01.01.2009 10:28

Да, в случае, если более новая версия изменит какой-либо публичный член на защищенный, SerializableVersionUID по умолчанию будет другим и вызовет InvalidClassExceptions.

Chander Shivdasani 13.01.2012 23:49

Имя класса, реализованные интерфейсы, все общедоступные и защищенные методы, ВСЕ переменные экземпляра.

Achow 01.03.2013 08:38

Стоит отметить, что Джошуа Блох советует для класса каждый Serializable указывать uid серийной версии. Цитата из главы 11: Независимо от того, какую сериализованную форму вы выберете, объявляйте явный UID последовательной версии в каждом сериализуемом классе, который вы пишете. Это исключает UID серийной версии как потенциальный источник несовместимости (элемент 74). Также есть небольшой выигрыш в производительности. Если не указан UID серийной версии, для его генерации во время выполнения требуются дорогостоящие вычисления.

Ashutosh Jindal 08.07.2014 17:25

Кажется актуальным. Ссылка на пару подходов к созданию UID серийной версии с использованием IDE: mkyong.com/java/how-to-generate-serialversionuid

Ben 20.12.2020 11:29

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

Window > Preferences > Java > Compiler > Errors / Warnings > Potential Programming Problems

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

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

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

проголосовать за, но только потому, что исходный постер, похоже, ничего не сериализирует. Если бы на плакате было написано: «Я сериализую эту штуку и ...», то вместо этого вы получите голос «против»: P

John Gardner 13.11.2008 04:28

Верно - я предполагал, что спрашивающий просто не хотел, чтобы его предупреждали

matt b 13.11.2008 05:52

@Gardner -> согласен! Но спрашивающий также хочет знать, почему он может не хотеть, чтобы его предупреждали.

Ziggy 01.01.2009 10:29

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

cinqS 18.04.2017 06:31

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

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

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

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

Tom Anderson 24.04.2011 14:43

Я не вижу, как добавление одной строки (аннотация @SuppressWarnings) в противоположность другой строке (сериализуемый идентификатор) «меньше загромождает класс». И если вы не используете сериализацию для постоянного хранения, почему бы вам просто не использовать «1»? В любом случае вам не будет важен автоматически сгенерированный идентификатор.

MetroidFan2002 25.04.2011 21:09

@ MetroidFan2002: Я думаю, что точка зрения @TomAnderson о том, что serialVersionUID защищает вас от несовместимых изменений, верна. Использование @SuppressWarnings лучше документирует намерение, если вы не хотите использовать класс для постоянного хранения.

AbdullahC 30.12.2011 18:32

«Вы должны увеличить его, если текущая версия вашего класса не имеет обратной совместимости с предыдущей версией:» Сначала вы должны изучить обширную поддержку управления версиями объектов в Serialization, (a) чтобы убедиться, что класс действительно теперь несовместим с сериализацией, чего по спецификации достичь довольно сложно; (b) попробовать такую ​​схему, как пользовательские методы чтения / записиObject (), методы readResolve / writeReplace (), объявления serializableFields и т. д., чтобы убедиться, что поток остается совместимым. Смена serialVersionUID - крайняя мера, совет отчаяния.

user207421 12.12.2012 04:59

@EJP приращение serialVersionUID появляется, когда первоначальный автор класса явно представил его. Я бы сказал, что сгенерированный jvm серийный идентификатор должен быть в порядке. это лучший отвечать, который я видел при сериализации.

overexchange 24.12.2014 18:39

@overexchange Что означает "явно введено"?

user207421 04.05.2015 14:17

Я имею в виду явно заявлено

overexchange 04.05.2015 14:27

@overexchange Вы имеете в виду «явно объявил» какие?

user207421 25.11.2017 12:11

@EJP Явно объявлен serialVersionUID.

overexchange 25.11.2017 12:13

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

john16384 10.02.2018 14:06

@TomAnderson По умолчанию в IDEA предупреждения не отображаются.

Alex78191 08.06.2018 03:53

@overexchange Я полностью согласен с ответом @JBNizet, но там ничего не говорится об увеличении serialVersionUID. Вы должны либо оставить его в покое, либо изменить его на новое вычисленное значение, как сообщает инструмент serialver, предварительно тщательно изучив альтернативы, о которых я упоминал, и еще до этого определенно определив, что это действительно нужно изменить, чего обычно не происходит '' т. Намеренно вводить несовместимые средства, особенно если они бесплатны, не дает никаких результатов.

user207421 26.07.2019 14:04

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

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

Paŭlo Ebermann 20.02.2011 05:04

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

Andrew Backer 09.08.2011 12:29

Не обязательно совпадать с тем, что будет производить serialver. -1

user207421 07.02.2014 05:10

В общем, это совсем не обязательно. В случае @ AndrewBacker потребуется два разных компилятора для одного и того же файла .java, при этом обе версии файлов .class будут взаимодействовать друг с другом - в большинстве случаев вы просто создаете класс и распространяете его. Если это так, то подойдет и отсутствие SUID.

Bill K 26.01.2018 00:06

Люди, которые действительно используют сериализацию для целей хранения / поиска, обычно устанавливают serialVersionUID на 1. Если более новая версия класса несовместима, но по-прежнему требует возможности обрабатывать старые данные, вы увеличиваете номер версии и добавляете специальный код. для работы со старыми форматами. Я плачу каждый раз, когда вижу serialVersionUID, размер которого превышает 1 цифру, либо потому, что это было случайное число (бесполезно), либо потому, что класс, по-видимому, должен иметь дело с более чем 10 различными версиями.

john16384 10.02.2018 14:11

Если вы получили это предупреждение в классе, о котором вы никогда не задумывались, и что вы не объявляли себя 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. Я думаю, что в этом случае не должно быть предупреждения (поскольку обычно вы не можете надежно сериализовать и десериализовать такие анонимные классы в любом случае в разных версиях вашего класса), но я не уверен, как компилятор мог это распознать.

Думаю, вы правы в том, что композиция важнее инертности, особенно когда вы обсуждаете такие классы, как ArrayList. Однако многие фреймворки требуют, чтобы люди расширялись от абстрактных суперклассов, которые можно сериализовать (например, класс ActionForm Struts 1.2 или Saxon ExtensionFunctionDefinition), и в этом случае это решение невозможно. Я думаю, что вы правы, было бы неплохо, если бы предупреждение игнорировалось в определенных случаях (например, если бы вы расширяли абстрактный сериализуемый класс)

piepera 07.12.2011 19:20

Конечно, если вы добавляете класс в качестве члена, а не наследуете от него, вам придется написать метод-оболочку для КАЖДОГО метода класса-члена, который вы хотите использовать, что сделает его невозможным в большом количестве ситуаций. ... если в java нет функции, подобной Perl __AUTOLOAD, о которой я не знаю.

M_M 20.08.2012 02:15

@M_M: Когда вы делегируете множество методов своему обернутому объекту, конечно, было бы нецелесообразно использовать делегирование. Но я полагаю, что этот случай является признаком ошибки дизайна - пользователям вашего класса (например, «MainGui») не нужно вызывать множество методов обернутого объекта (например, JFrame).

Paŭlo Ebermann 20.08.2012 12:09

Что мне не нравится в делегировании, так это необходимость содержать ссылку на делегата. И каждая ссылка означает больше памяти. Поправьте меня если я ошибаюсь. Если мне нужен CustomizedArrayList из 100 объектов, это не имеет большого значения, но если мне нужны сотни CustomizdeArrayList из нескольких объектов, использование памяти значительно возрастет.

WVrock 29.11.2014 10:14

Throwable можно сериализовать, и только Throwable можно выбросить, поэтому невозможно определить исключение, которое не сериализуемо. Делегирование невозможно.

Phil 13.04.2017 05:59

@Phil Я думаю, что это сделано намеренно - даже если вы не хотите сериализовать свой класс исключения, кто-то другой может захотеть сериализовать созданное вами исключение. (Конечно, можно утверждать, что большинство классов исключений должно работать с автоматически сгенерированным serialVersionUID и не нуждаться в фиксированном.)

Paŭlo Ebermann 18.04.2017 10:38

@WVrock Что ж, ничего бы не изменилось, если бы у вас было множество экземпляров ArrayList. Экземпляр вашего класса-оболочки имеет размер порядка байтов + размер arrayylist, тогда как посредством наследования вы инициализируете такое же количество, но в соответствии с определением 1 класса. Ссылки легкие, лежащие в основе объекты тяжелые.

Rogue 13.06.2017 16:42

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

Мусор. Достаточно в том случае, если класс не изменился. У вас нет никаких доказательств, подтверждающих «99,9999%».

user207421 22.03.2018 13:30

Проблема не в том, что он «плохой», но нет гарантии, что он будет соответствовать разным версиям.

Dorian Gray 03.11.2020 18:44

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

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

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

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

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

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

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

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

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

Добавление или удаление непереходных полей не делает класс несовместимым с сериализацией. Следовательно, нет никаких причин «навязывать» такие изменения.

user207421 07.02.2014 05:05

@EJP: А? Добавление данных определенно меняет данные сериализации в моем мире.

Alexander Torstling 07.02.2014 23:12

@AlexanderTorstling Прочтите, что я написал. Я не сказал, что это не «меняет данные сериализации». Я сказал, что это «не делает сериализацию классов несовместимой». Это не одно и то же. Вам необходимо прочитать главу «Управление версиями» Спецификации сериализации объектов.

user207421 21.05.2014 01:27

@EJP: Я понимаю, что добавление непереходного поля не обязательно означает, что вы делаете класс несовместимым с сериализацией, но это структурное изменение, которое изменяет сериализованные данные, и вы обычно хотите поднять версию при этом, если вы не обрабатывать обратную совместимость, что я также объяснил позже в этом посте. Что именно вы хотите сказать?

Alexander Torstling 21.05.2014 10:42

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

user207421 04.05.2015 14:16

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

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

@SuppressWarnings("serial")

В исходном вопросе был задан вопрос «почему это важно» и «пример», в котором этот Serial Version ID был бы полезен. Я нашел одну.

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

public class Car {
    static final long serialVersionUID = 1L; //assign a long value
}

И каждому UID следует присвоить случайное длинное число, а не 1L.

abbas 27.10.2017 04:34

@abbas 'Надо' так почему? Пожалуйста, объясните, в чем разница.

user207421 25.11.2017 11:58

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

abbas 27.11.2017 03:39

@abbas, это намерение не противоречит использованию увеличивающихся натуральных чисел из 1 и так далее.

Vadzim 14.12.2017 21:21

@BillK, я думал, что проверка сериализации привязана к паре classname и serialVersionUID. Так что разные схемы нумерации разных классов и библиотек никак не могут мешать. Или вы имели в виду библиотеки для генерации кода?

Vadzim 26.01.2018 13:26

@abbas serialVersionUID не имеет ничего общего с «поиском правильной версии класса».

user207421 22.03.2018 13:28

То, что я всегда находил безумным, заключалось в том, что алгоритм получения serialVersionUID, когда ни один явно не объявлен, основан на пакете, имени, атрибутах, но ТАКЖЕ методы ... методы не сериализуются, и добавление / удаление методов не влияет на сериализованную форму объект, так зачем создавать другой serialVersionUID при добавлении / удалении / изменении метода »?

Volksman 02.05.2020 13:35

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

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

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

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

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

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

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

Алгоритм не меняется, но он немного занижен.

user207421 21.05.2014 01:35

... алгоритм не меняется, но он немного недооценен ... это означает, что любой jvm может отличаться ..... @ user207421

AnthonyJClink 30.08.2019 04:01

What is a serialVersionUID and why should I use it?

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

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

javadocs для Serializable говорят:

the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected InvalidClassExceptions during deserialization.

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

У эта статья есть несколько хороших моментов по этой теме.

@Vinothbabu, но serialVersionUID является статическим, поэтому статические переменные не могут быть сериализованы. тогда почему jvm проверит версию, не зная, какая версия десериализуемого объекта

Kranthi Sama 16.06.2014 15:06

В этом ответе не упоминается одна вещь: вы можете вызвать непредвиденные последствия, слепо включив serialVersionUID, не зная почему. Комментарий Тома Андерсона к ответу MetroidFan2002 касается этого: «Я бы сказал, что если вы не используете сериализацию для постоянного хранения, вам следует использовать @SuppressWarnings, а не добавлять значение. Это меньше загромождает класс и сохраняет способность Механизм serialVersionUID для защиты от несовместимых изменений. "

Kirby 17.06.2014 20:30
serialVersionUID - это нет, «уникальный идентификатор для каждого класса». Это полное имя класса. Это индикатор версия.
user207421 09.06.2015 07:17

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

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

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

@SuppressWarnings("serial")

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

Он не включает HttpServlet в контейнеры, где они могут быть заменены, или Exception в RMI, например.

user207421 21.05.2014 01:36

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

Подробнее: http://javarevisited.blogspot.com/2011/04/top-10-java-serialization-interview.html#ixzz3VQxnpOPZ

Если вы хотите изменить огромное количество классов, для которых в первую очередь не задан 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

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

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

Ignazio 17.03.2016 21:05

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

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

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

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

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

Каждый раз, когда класс объекта сериализуется, передается serialVersionUID. Он не отправляется с каждым объектом.

user207421 25.11.2017 12:00

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

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

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

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

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

Сначала мне нужно объяснить, что такое сериализация.

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

Есть некоторые правила сериализации.

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

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

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

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

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

Когда Object сериализуется, среда выполнения Java связывает серийный номер версии, также известный как 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() {
        return getEmpName() + " is " + getEmpAge() + "years old";
    }
}

Создать сериализованный объект

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)

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

Victor 03.06.2020 16:03

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Что такое SerialVersionUID? Ответ: - Допустим, есть два человека, один из штаб-квартиры, а другой из ODC, оба будут выполнять сериализацию и десериализацию соответственно. В этом случае для подтверждения того, что получатель, находящийся в ODC, является аутентифицированным лицом, JVM создает уникальный идентификатор, который известен как SerialVersionUID.

Вот хорошее объяснение, основанное на сценарии,

Почему именно SerialVersionUID?

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

Десериализация: во время десериализации JVM на стороне получателя будет сравнивать уникальный идентификатор, связанный с объектом, с уникальным идентификатором локального класса, то есть JVM также создаст уникальный идентификатор на основе соответствующего файла .class, который присутствует в системе получателя. Если оба уникальных идентификатора совпадают, будет выполнена только десериализация. В противном случае мы получим исключение времени выполнения с сообщением InvalidClassException. Этот уникальный идентификатор - не что иное, как SerialVersionUID.

serialVersionUID - это 64-битное число, используемое для уникальной идентификации класса в процессе десериализации. Когда вы сериализуете объект, serialVersionUID класса также записывается в файл. Всякий раз, когда вы десериализуете этот объект, среда выполнения java извлекает это значение serialVersionUID из сериализованных данных и сравнивает то же значение, связанное с классом. Если оба не совпадают, будет выбрано исключение java.io.InvalidClassException.

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

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