Сериализация Java со статической инициализацией

В Java статические и временные поля не сериализуются. Однако я обнаружил, что инициализация статических полей приводит к изменению сгенерированного serialVersionUID. Например, static int MYINT = 3; вызывает изменение serialVersionUID. В этом примере это имеет смысл, потому что разные версии класса будут иметь разные начальные значения. Почему при любой инициализации изменяется serialVersionUID? Например, static String MYSTRING = System.getProperty("foo"); также вызывает изменение serialVersionUID.

Чтобы быть конкретным, мой вопрос: почему инициализация с помощью метода вызывает изменение serialVersionUID. Проблема, с которой я столкнулся, заключается в том, что я добавил новое статическое поле, которое было инициализировано значением системного свойства (getProperty). Это изменение вызвало исключение сериализации при удаленном вызове.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
8
0
3 283
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Если я правильно прочитал спецификацию, автоматический serialVersionUID не должен измениться, если вы измените значение статического или переходного поля. Взгляните на Глава 5.6 спецификации.

тем не мение, если вы немного задумаетесь - вы начинаете с сериализации объекта, имеющего static int MYINT = 3, а затем десериализуете класс, который ожидаете получить обратно, то есть с MYINT = 3. Итак, если вы измените статическую инициализацию, вы ожидаете, что serialVersionUID изменится, потому что вы не можете вернуть тот же объект снова.

В любом случае, сохраните это во всех сериализуемых классах, и вы можете управлять serialVersionUID:

private static final long serialVersionUID = 7526472295622776147L;

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

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

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

Вы можете найти некоторую информацию об этом в ошибка 4365406 и в алгоритм вычисления serialVersionUID. По сути, при изменении инициализации вашего члена static с помощью System.getProperty() компилятор вводит новое свойство static в вашем классе, ссылающееся на класс System (я предполагаю, что класс System ранее не упоминался в вашем классе), и поскольку это свойство было введено компилятором не является частным, он участвует в вычислении serialVersionUID.

Мораль: всегда используйте явный serialVersionUID, вы сэкономите несколько циклов процессора и некоторые головные боли :)

Автоматический serialVersionUID вычисляется на основе членов класса. Их можно показать для файла класса с помощью инструмента javap в Sun JDK.

В случае, упомянутом в вопросе, добавляемый / удаляемый член является статическим инициализатором. Это отображается как () V в файлах классов. Содержимое метода можно разобрать с помощью javap -c. Вы должны уметь различать вызов System.getProperty ("foo") и назначение MYSTRING. Однако назначение со строковым литералом (или любой константой времени компиляции, как определено в спецификации языка Java) поддерживается непосредственно файлом класса, что устраняет необходимость в статическом инициализаторе.

Распространенным случаем для кода, ориентированного на J2SE 1.4 (используйте -source 1.4 -target 1.4) или более ранней версии, являются статические поля для старых экземпляров класса, которые отображаются как литералы класса в исходном коде (MyClass.class). Экземпляр класса ищется по запросу с помощью Class.forName и сохраняется в статическом поле. Именно это статическое поле нарушает serialVersionUID. Начиная с J2SE 5.0, вариант кода операции ldc обеспечивает прямую поддержку литералов класса, устраняя необходимость в синтетическом поле. Опять же, все это можно показать с помощью javap -c.

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