почему небезопасно полагаться на ObjectStreamClass.getSerialVersionUID?

В спецификации java говорится: «настоятельно рекомендуется, чтобы все сериализуемые классы явно объявляли значения serialVersionUID, поскольку вычисление serialVersionUID по умолчанию очень чувствительно к деталям класса, которые могут варьироваться в зависимости от реализаций компилятора»

Пожалуйста, мог бы кто-нибудь вникнуть в это? Метод getSerialVersionUID () выполняет отражение, а отражение обычно используется повсюду, так что же зависит от компилятора?


person ejaenv    schedule 07.12.2016    source источник


Ответы (1)


Блестящее объяснение этого вопроса дано в книге Дж. Блоха «Эффективная Java»:

«Правило 74: разумно реализуйте сериализуемые»:

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

UPD: в комментариях меня также спросили, почему это зависит от компилятора. На самом деле зависимость от компилятора здесь не в самом алгоритме getSerialVersionUID() (метод вызывается во время выполнения, конечно), а в том, как описывается сам класс. Например, некоторые синтетические методы могут быть добавлены в класс во время компиляции, что также будет учитываться в SUID. Подробнее см. В методе ObjectStreamClass.computeDefaultSUID(), его функциях и способах вычисления SUID по умолчанию.

person Andremoniy    schedule 07.12.2016
comment
но это объяснение не говорит, почему это зависит от компилятора. Используется ли getSerialVersionUID () в реальном времени для вычисления значения? - person ejaenv; 07.12.2016
comment
@ejaenv, посмотри мой апд - person Andremoniy; 07.12.2016
comment
Даже без зависимостей компилятора вы не захотите использовать алгоритм, который считает постоянную форму несовместимой, когда вы изменяете static поля или методы. Даже наличие у класса инициализатора имеет значение. В тексте цитаты не упоминается, что учитываются не только «все его общедоступные и защищенные члены», но также и все частные члены пакета, поэтому синтетические методы, такие как внутренние средства доступа к классу, имеют значение ... - person Holger; 07.12.2016
comment
IMO computeDefaultSUID следует заменить на полезный. - person ejaenv; 07.12.2016
comment
@ejaenv: ну, изменение алгоритма нарушит совместимость со всеми существующими сериализованными данными, а также будет означать, что данные, хранящиеся с использованием нового алгоритма, будут отклонены более старыми JRE. - person Holger; 08.12.2016