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




Если я правильно прочитал спецификацию, автоматический 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.