Serialization и SerialVersionUID всегда остается загадкой для многих Java-разработчиков. Я часто вижу вопросы насчет того что такое SerialVersionUID, или что произойдет, если я не объявлю SerialVersionUID в моем Serializable-классе?
Помимо запутанного и редкого использования, есть еще одна причина для этого вопроса — это предупреждение Eclipse IDE об отсутствии SerialVersionUID, например: "The Serializable class Customer does not declare a static final SerialVersionUID field of type long" ("Serializable-класс Customer не объявил статическое финальное поле SerialVersionUID типа long").
В этой статье, вы сможете не только узнать основы Java SerialVersionUID но и его влияние на процесс сериализации и де-сериализации. Когда вы объявляете класс, как Serializable путем реализации интерфейса-маркера java.io.Serializable, среда выполнения Java сохраняет экземпляр этого класса на диске с помощью механизма сериализации по умолчанию, если вы не настроили процесс использования интерфейса Externalizable.
Во время сериализации, среда выполнения Java создает номер версии для класса, так что она может десереализировать его позже. В Java этот номер версии известен как SerialVersionUID. Если во время десериализации, SerialVersionUID не соответствует, то процесс завершится с исключением InvalidClassException в потоке "main" java.io.InvalidClassException, а также напечатает имя класса и соответствующий SerialVersionUID. Быстрое решение для исправления этой проблемы – скопировать SerialVersionUID и определить его как константу типа privatestaticfinallong в вашем классе. В этой статье мы узнаем, о том, почему мы должны использовать SerialVersionUID в Java и как использовать инструмент serialver JDK для генерации этого ID.
Если вы новичок в сериализации, вы также можете посмотреть Топ 10 вопросов о сериализации Java на интервью чтобы оценить свои знания и найти пробелы в вашем понимании для дальнейшего чтения. Подобно Concurrency (параллельности) и Multi-threading (многопоточности), Serialization (сериализация) это уже другая тема, которая заслуживает чтения несколько раз.
Зачем использовать SerialVersionUID в Java
Как я сказал, когда мы не определилили значение SerialVersionUID как staticfinallong в нашем классе, механизм сериализации сделает это за нас. Этот механизм чувствителен ко многим деталям, включая поля вашего класса, их модификаторы доступа, интерфейсы, которые он реализует и даже различные реализации компилятора, любые изменения в классе или использование другого компилятора может дать результат иного SerialVersionUID, который в конечном итоге остановит перезагрузку сериализованных данных.Очень рискованно полагаться на механизм сериализации Java для генерации этого id, вот почему рекомендуется явно определять SerialVersionUID в вашем Serializable-классе. Я настоятельно советую прочитать классику Java — Joshua Bloch “Effective Java” для понимания сериализации Java и проблем неправильной их обработки.
Кстати, JDK также предоставляет инструмент serialver, который расположен в директории bin каталога JAVA_HOME, на моем компьютере C:\Program Files\Java\jdk1.6.0_26\bin\serialver.exe, который может быть использован для генерирования SerialVersionUID для старых классов. Это очень полезно в случае, если вы внесли изменения в ваш класс, который нарушает сериализацию и ваше приложение не может перезагрузить сериализированные экземпляры. Вы легко можете использовать эту утилиту для создания SerialVersionUID для старых экземпляров, а затем использовать его в явном виде объявив поле как privatestaticfinallongSerialVersionUID. Кстати, очень рекомендуется из соображений производительности и безопасности использовать обычный двоичный формат для сериализации, опять же “Effective Java” имеет несколько параграфов, которые демонстрируют преимущества обычного формата в мельчайших деталях.
Как использовать утилиту serialver JDK для генерирования SerialVersionUID
Вы можете использовать serialver для генерирования SerialVersionUID для классов. Это особенно полезно для развивающихся классов, утилита возвращает SerialVersionUID в формате легком для копирования. Вы можете использовать утилиту serialver JDK как показано в примере:
$ serialver
use: serialver [-classpath classpath] [-show] [classname...]
$ serialver -classpath . Hello
Class Hello is not Serializable.
$ serialver -classpath . Hello
Hello: static final long SerialVersionUID = -4862926644813433707L;
Вы также можете использовать утилиту serialver в GUI виде используя команду $ serialver –show, это откроет инспектор serial version, который принимает полное имя класса и показывает его Serial version.
Резюме
Теперь мы знаем что такое SerialVersionUID и почему важно объявлять его в Serializable-классе, самое время пересмотреть некоторые важные факты связанные с Java SerialVersionUID.
SerialVersionUID используется для указании версии сериализованных данных.
Когда мы не объявляем SerialVersionUID в нашем классе, среда выполнения Java делает это за нас, но этот процесс чувствителен ко многим метаданным класса включая количество полей, тип полей, модификаторы доступа полей, интерфейсов, которые реализованы в классе и пр. Вы можете найти точную информацию в документации о сериализации от Oracle.
Рекомендуется объявлять SerialVersionUID как private static final long переменную во избежание механизма по умолчанию. Некоторые IDE, такие как Eclipse, также выдают предупреждения если вы забыли это, например: "The Serializable class Customer does not declare a static final SerialVersionUID field of type long" ("Serializable-класс Customer не объявил статическое финальное поле SerialVersionUID типа long"). Хотя вы и можете отключить это предупреждение следуя в Window > Preferences > Java > Compiler > Errors / Warnings > Potential Programming Problems, я предлагаю не делать этого. Только когда восстановление данных не требуется я могу быть небрежным в этом. Вот как эта ошибка выглядит в Eclipse IDE, все что вам нужно это принять первое быстрое решение.
Вы также можете использовать утилиту serialver из JDK для генерирования Serial Version для классов в Java. Утилита также имеет GUI, который включается при передаче параметра – show.
Лучшая практика в сериализации – это явно объявить SerialVersionUID, чтобы избежать любых проблем при де-сериализации, особенно если вы работаете с клиент-серверным приложением, которое опирается на сериализованные данные, например, RMI.
Это все про SerialVersionUID в Java. Сейчас мы знаем почему важно правильно объявлять SerialVersionUID в классе. Вы можете сказать спасибо вашей IDE за это напоминание, которое потенциально может нарушить де-сериализацию вашего класса.
Если вы хотите больше прочитать про сериализацию и родственные понятия, вы можете также посмотреть эти удивительные статьи.
Вот это я нашёл
File → Setting → Editor → Inspections → JVM languages → Serializable class without 'serialVersionUID'
Не понял как classpath указывать в утилите serialver
К сожалению настройка не дает эффекта. Изменение не подсвечивается, в ручную создать не получается.
Путь такой File → Setting → Editor → Inspections → Java → Serialization issues → Serializable class without 'serialVersionUID' - установите флаг и нажмите 'OK'
Конечная точка слегка другая Serializable non-static inner class without 'serialVersionUID
Хз что делать мб кто-то поможет.
Вдруг кому нужно, как в Idea IDE генерить serialVersionUID:
File → Setting → Editor → Inspections → Java → Serialization issues → Serializable class without 'serialVersionUID' - установите флаг и нажмите 'OK'.
Теперь, если ваш класс реализует Serializable, вы увидите предупреждение, и alt+Enter для имени класса сгенерирует private static final long serialVersionUID.
В пункте "Зачем использовать SerialVersionUID ?" в Java автор рассуждает о чувствительности механизма, советует нам почитать книгу, рассказывает что есть утилита чтоб узнать SerialVersionUID и как ей пользоваться. В общем делает все кроме ответа на поставленный в заголовке вопрос.
Вода бесполезная а не статья!
Не используешь свой SerialVersionUID >> джава создаст дефолтный
Дефолтный SerialVersionUID изменчивый
Поменяешь переменную в классе >> изменится дефолтный SerialVersionUID
Попытаешься десериализировать объект с отличающимся SerialVersionUID >> исключение
Я, конечно, всё понимаю, но, по-моему, из статьи всё очевидно...
(А "Топ 10 вопросов о сериализации Java на интервью" мне показалась очень полезной)
Если кому интересно как еще можна узнать этот айдишник с IDE, то вот нагуглил и проверил. Вроде все ок!
public class GettingSerialVersionUIDForJavaClass implements Serializable {
private int i = 1;
public String text = "qwerty";
//Если активизируем эту строку то будет выводиться 1 (единица)
// private static final long serialVersionUID = 1L; //
public static void main(String[] args) {
GettingSerialVersionUIDForJavaClass myClass = new GettingSerialVersionUIDForJavaClass();
ObjectStreamClass c = ObjectStreamClass.lookup(myClass.getClass());
long serialID = c.getSerialVersionUID();
System.out.println(serialID); //у меня выводит 4243016409269090130
}
}
У меня вот вопрос остался, если я добавлю явно SerialVersionUID = 1 (например) , и сериализую объект cat (например а унего будет поле ссылочного типа энимал напрмер ), а потом скажем я изменю класс так что этого поля больше не будет, обратно при десириализации что произойдет? SerialVersionUID - будет подходящий я его скажем оставлю таким же в классе. какое то исключение должно выброситься?
будет беда, сам же понимаешь)
поэтому, поменял структуру класса - обновил SerialVersionUID: поставил 2 например, потом 3, 4, итд. ну или попросить ИДЕ сгенерить новый айдишник, но делать это при каждом изменении в классе.
тогда логично, что старые объекты уже не десериализуются (потому что это невозможно, ведь ты реально удалил поле в классе), но вот новые - будут нормально сериализоваться-десериализовываться с этим новым айдишником
В Идее предупреждение об отсутствии serialVersionUID включить не сложно.
Заходим в Preferences / Inspections / Java / Serialization issues и ставим галочку в чек-бокс Serializable class without serialVersionUID.
Хорошая статья. Благодаря Вам разобрался от и до. Сделал тестовые примеры, менял SerialVersionUID и смотрел что получается. Единственное замечание...
Переменная serialVersionUID именно с маленькой буквы !!!. Иначе мы просто объявляем статистическую переменную класса SerialVersionUID, которая совсем не зависит от serialVersionUID.
Потратил больше часа на это :) Но... Благодаря этому сериализую с подменой и установкой начального значения serialVersionUID разные версии класса с закрытыми глазами :)
Такое ощущение, что СЕОшник чужую статью рерайтил. Повторы, повторы, повторы в разных комбинациях... Хорошо, что в этой статье мы узнали, о том, почему мы должны использовать SerialVersionUID в Java.
Спасибо за статью. Кратко и по делу. Вопрос лишь по целесообразности использования утилит подобных serialver . Зачем генерировать какие-то числа, разве не проще использовать понятную автору нумерацию версий нашего класса определяемую порядком написания кода?
P.S. Подскажите пожалуйста, правильно ли я понимаю, что у классов, реализующих интерфейс Externalizable нет поля SerialVersionUID по умолчанию, это привилегия только Serializable?
P.P.S. И ещё вопрос. Как я понял, SerialVersionUID может измениться только если поменяются поля класса. Методы их количество и порядок написания не влияют на SerialVersionUID ? Или влияют?
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ