Что такое serialVersionUID и почему я должен его использовать?
Eclipse выдает предупреждения, когда serialVersionUID
пропал, отсутствует.
Сериализуемый класс Foo не объявляет статическое окончательное поле serialVersionUID типа long
Что такое serialVersionUID
и почему это важно? Пожалуйста, покажите пример, где отсутствует serialVersionUID
вызовет проблему.
22 ответа
Документы для java.io.Serializable
вероятно, такое же хорошее объяснение, как вы получите:
Среда выполнения сериализации связывает с каждым сериализуемым классом номер версии, называемый
serialVersionUID
, который используется во время десериализации для проверки того, что отправитель и получатель сериализованного объекта загрузили классы для этого объекта, которые совместимы в отношении сериализации. Если получатель загрузил класс для объекта, который имеет другойserialVersionUID
чем класс соответствующего отправителя, то десериализация приведет кInvalidClassException
, Сериализуемый класс может объявить свой собственныйserialVersionUID
явно объявив поле с именемserialVersionUID
это должно быть статическим, окончательным и типомlong
:ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
Если сериализуемый класс явно не объявляет
serialVersionUID
тогда во время выполнения сериализации будет вычислено значение по умолчаниюserialVersionUID
значение для этого класса, основанное на различных аспектах класса, как описано в Спецификации Сериализации Объекта Java(TM). Однако настоятельно рекомендуется, чтобы все сериализуемые классы явно объявлялиserialVersionUID
значения, так как по умолчаниюserialVersionUID
вычисления очень чувствительны к деталям класса, которые могут варьироваться в зависимости от реализации компилятора, и, следовательно, могут привести к неожиданнымInvalidClassExceptions
во время десериализации. Поэтому, чтобы гарантировать последовательноеserialVersionUID
значение в различных реализациях Java-компилятора, сериализуемый класс должен объявить явноеserialVersionUID
значение. Также настоятельно рекомендуется, чтобыserialVersionUID
в объявлениях по возможности используется модификатор private, поскольку такие объявления применяются только к классу, который был немедленно объявленserialVersionUID
поля не полезны как унаследованные члены.
Если вы сериализуете только потому, что вы должны сериализовать ради реализации (кого волнует, если вы сериализуете для HTTPSession
например, если он хранится или нет, вы, вероятно, не заботитесь о de-serializing
объект формы), то вы можете игнорировать это.
Если вы на самом деле используете сериализацию, это имеет значение, только если вы планируете хранить и извлекать объекты, используя сериализацию напрямую. serialVersionUID
представляет версию вашего класса, и вы должны увеличить ее, если текущая версия вашего класса не имеет обратной совместимости с предыдущей версией.
В большинстве случаев вы, вероятно, не будете использовать сериализацию напрямую. Если это так, создайте значение по умолчанию SerialVersionUID
нажав на кнопку быстрого исправления и не беспокойтесь об этом.
Я не могу упустить эту возможность, чтобы включить книгу Джоша Блоха " Эффективная Java" (2-е издание). Глава 11 является обязательным ресурсом по сериализации Java.
Согласно Джошу, автоматически сгенерированный UID генерируется на основе имени класса, реализованных интерфейсов и всех открытых и защищенных членов. Изменение любого из них любым способом изменит serialVersionUID
, Поэтому вам не нужно связываться с ними, только если вы уверены, что не более одной версии класса никогда не будет сериализовано (либо между процессами, либо получено из хранилища позднее).
Если вы игнорируете их сейчас и обнаружите позже, что вам нужно каким-то образом изменить класс, но сохранить совместимость со старой версией класса, вы можете использовать инструментальный сериал JDK для генерации serialVersionUID
на старом классе, и явно установите это на новом классе. (В зависимости от ваших изменений может потребоваться также реализовать пользовательскую сериализацию, добавив writeObject
а также readObject
методы - см. Serializable
Javadoc или вышеупомянутая глава 11.)
Вы можете указать Eclipse игнорировать эти предупреждения serialVersionUID:
Окно> Настройки> Java > Компилятор> Ошибки / Предупреждения> Потенциальные проблемы программирования
В случае, если вы не знали, есть много других предупреждений, которые вы можете включить в этом разделе (или даже сообщить о некоторых ошибках), многие из них очень полезны:
- Потенциальные проблемы программирования: возможное случайное логическое назначение
- Потенциальные проблемы программирования: доступ с нулевым указателем
- Ненужный код: локальная переменная никогда не читается
- Ненужный код: избыточная нулевая проверка
- Ненужный код: Ненужный приведение или 'instanceof'
и многое другое.
serialVersionUID
облегчает управление версиями сериализованных данных. Его значение сохраняется вместе с данными при сериализации. При десериализации, эта же версия проверяется, чтобы увидеть, как сериализованные данные соответствуют текущему коду.
Если вы хотите создать версию ваших данных, вы обычно начинаете с serialVersionUID
0, и увеличивайте его при каждом структурном изменении вашего класса, которое изменяет сериализованные данные (добавляя или удаляя непереходные поля).
Встроенный механизм десериализации (in.defaultReadObject()
) откажется от десериализации старых версий данных. Но если вы хотите, вы можете определить свою собственную функцию readObject(), которая может считывать старые данные. Этот пользовательский код может затем проверить serialVersionUID
чтобы узнать, в какой версии находятся данные, и решить, как десериализовать их. Этот метод управления версиями полезен, если вы храните сериализованные данные, которые сохраняются в нескольких версиях вашего кода.
Но хранение сериализованных данных в течение такого длительного промежутка времени не очень распространено. Гораздо более распространенным является использование механизма сериализации для временной записи данных, например, в кэш или отправки их по сети в другую программу с той же версией соответствующих частей кодовой базы.
В этом случае вы не заинтересованы в поддержании обратной совместимости. Вы заинтересованы только в том, чтобы убедиться, что базы кода, которые общаются, действительно имеют одинаковые версии соответствующих классов. Чтобы облегчить такую проверку, вы должны поддерживать serialVersionUID
так же, как и раньше, и не забудьте обновить его при внесении изменений в ваших классах.
Если вы забудете обновить поле, вы можете получить две разные версии класса с разной структурой, но с одинаковой serialVersionUID
, Если это произойдет, механизм по умолчанию (in.defaultReadObject()
) не обнаружит никакой разницы и попытается десериализовать несовместимые данные. Теперь вы можете получить загадочную ошибку во время выполнения или тихий сбой (пустые поля). Эти типы ошибок могут быть трудно найти.
Таким образом, чтобы помочь этому варианту использования, платформа Java предлагает вам не устанавливать serialVersionUID
вручную. Вместо этого, хэш структуры класса будет сгенерирован во время компиляции и использован как идентификатор. Этот механизм гарантирует, что у вас никогда не будет разных структур классов с одинаковым идентификатором, и поэтому вы не получите этих трудно отслеживаемых ошибок сериализации во время выполнения, упомянутых выше.
Но есть и обратная сторона автоматически генерируемой стратегии id. А именно, что сгенерированные идентификаторы для одного и того же класса могут отличаться в разных компиляторах (как упомянуто Джоном Скитом выше). Поэтому, если вы передаете сериализованные данные между кодом, скомпилированным с разными компиляторами, рекомендуется в любом случае поддерживать идентификаторы вручную.
И если вы обратно совместимы с вашими данными, как в первом упомянутом случае использования, вы также, вероятно, захотите сохранить идентификатор самостоятельно. Это для того, чтобы получить читаемые идентификаторы и иметь больший контроль над тем, когда и как они меняются.
Что такое serialVersionUID и почему я должен его использовать?
SerialVersionUID
это уникальный идентификатор для каждого класса, JVM
использует его для сравнения версий класса, обеспечивающих загрузку во время десериализации одного и того же класса во время сериализации.
Указание одного дает больше контроля, хотя JVM генерирует его, если вы не укажете. Сгенерированное значение может отличаться для разных компиляторов. Кроме того, иногда вы просто хотите по какой-то причине запретить десериализацию старых сериализованных объектов [ backward incompatibility
], и в этом случае вам просто нужно изменить serialVersionUID.
Javadocs для Serializable
сказать:
вычисление serialVersionUID по умолчанию очень чувствительно к деталям класса, которые могут различаться в зависимости от реализаций компилятора и, таким образом, могут привести к непредвиденным
InvalidClassException
S во время десериализации.
Следовательно, вы должны объявить serialVersionUID, потому что это дает нам больше контроля.
Эта статья имеет несколько положительных моментов по теме.
В первоначальном вопросе спрашивалось "почему это важно" и "пример", где это 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
}
Сначала мне нужно объяснить сериализацию.
Сериализация позволяет преобразовать объект в поток для отправки этого объекта по сети ИЛИ сохранить в файл ИЛИ сохранить в БД для использования в письме.
Есть несколько правил для сериализации.
Объект является сериализуемым, только если его класс или его суперкласс реализуют интерфейс Serializable.
Объект является сериализуемым (сам реализует интерфейс Serializable), даже если его суперкласс - нет. Однако первый суперкласс в иерархии сериализуемого класса, который не реализует интерфейс Serializable, ДОЛЖЕН иметь конструктор без аргументов. Если это нарушено, readObject() создаст java.io.InvalidClassException во время выполнения
Все примитивные типы являются сериализуемыми.
Переходные поля (с модификатором переходного процесса) НЕ сериализуются (т.е. не сохраняются и не восстанавливаются). Класс, реализующий Serializable, должен отмечать переходные поля классов, которые не поддерживают сериализацию (например, файловый поток).
Статические поля (со статическим модификатором) не сериализуются.
Когда объект сериализуется, JAVA Runtime связывает серийный номер версии, который называется 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() {
StringBuffer employee = new StringBuffer();
employee.append(getEmpName()).append(" is ).append(getEmpAge()).append("
years old "));
return employee.toString();
}
}
Создать объект сериализации
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)
Если вам никогда не понадобится сериализовать ваши объекты в байтовый массив и отправить / сохранить их, вам не нужно об этом беспокоиться. Если вы это сделаете, то вы должны рассмотреть ваш serialVersionUID, поскольку десериализатор объекта будет сопоставлять его с версией объекта, которую имеет его загрузчик классов. Узнайте больше об этом в Спецификации языка Java.
Если вы получаете это предупреждение в классе, вы никогда не думаете о сериализации, и что вы не объявили себя 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-метод. Я думаю, что в этом случае не должно быть предупреждения (так как обычно вы не можете надежно сериализовать и десериализовать такие анонимные классы в любом случае между различными версиями вашего класса), но я не уверен, как компилятор мог распознать это.
Чтобы понять значение поля serialVersionUID, необходимо понять, как работает сериализация / десериализация.
Когда сериализуемый объект класса сериализуется, Java Runtime связывает серийный номер версии (называемый serialVersionUID) с этим сериализованным объектом. Во время десериализации этого сериализованного объекта Java Runtime сопоставляет 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.
Что касается примера, где отсутствующий serialVersionUID может вызвать проблему:
Я работаю над этим приложением Java EE, которое состоит из веб-модуля, который использует EJB
модуль. Веб-модуль вызывает EJB
модуль удаленно и передает POJO
который реализует Serializable
в качестве аргумента.
это POJO's
класс был упакован в EJB-банку и в свою собственную флягу в 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
Не беспокойтесь, расчет по умолчанию действительно хорош и достаточен для 99,9999% случаев. И если вы столкнетесь с проблемами, вы можете - как уже было сказано - вводить UID как необходимость (что весьма маловероятно)
Я вообще пользуюсь serialVersionUID
в одном контексте: когда я знаю, это будет выходить из контекста Java VM.
Я знал бы это, когда я использую ObjectInputStream
а также ObjectOutputStream
для моего приложения или, если я знаю, библиотека / фреймворк, который я использую, будет использовать его. SerialVersionID гарантирует, что разные виртуальные машины Java разных версий или поставщиков будут правильно взаимодействовать или, например, если они хранятся и извлекаются за пределами виртуальной машины HttpSession
данные сеанса могут сохраняться даже во время перезапуска и обновления сервера приложений.
Для всех остальных случаев я использую
@SuppressWarnings("serial")
так как большую часть времени по умолчанию serialVersionUID
достаточно. Это включает Exception
, HttpServlet
,
Данные поля представляют некоторую информацию, хранящуюся в классе. Класс реализует Serializable
интерфейс, поэтому Eclipse автоматически предлагает объявить serialVersionUID
поле. Давайте начнем со значения 1, установленного там.
Если вы не хотите, чтобы это предупреждение появилось, используйте это:
@SuppressWarnings("serial")
Зачем использовать SerialVersionUID
внутри Serializable
класс в Java?
В течение serialization
Среда выполнения Java создает номер версии для класса, чтобы он мог десериализовать его позже. Этот номер версии известен как SerialVersionUID
на Яве.
SerialVersionUID
используется для версии сериализованных данных. Вы можете десериализовать класс, только если он SerialVersionUID
совпадает с сериализованным экземпляром. Когда мы не объявляем SerialVersionUID
в нашем классе среда выполнения Java генерирует его для нас, но это не рекомендуется. Рекомендуется объявить SerialVersionUID
как private static final long
переменная, чтобы избежать механизма по умолчанию.
Когда вы объявляете класс как Serializable
путем реализации интерфейса маркера java.io.Serializable
Среда выполнения Java сохраняет экземпляр этого класса на диске, используя механизм сериализации по умолчанию, при условии, что вы не настроили процесс, используя Externalizable
интерфейс.
см. также Зачем использовать SerialVersionUID внутри класса Serializable в Java
SerialVersionUID используется для контроля версий объекта. вы также можете указать serialVersionUID в вашем файле класса. Следствием отсутствия указания serialVersionUID является то, что при добавлении или изменении какого-либо поля в классе уже сериализованный класс не сможет восстановиться, поскольку serialVersionUID, сгенерированный для нового класса и для старого сериализованного объекта, будет отличаться. Процесс сериализации Java использует правильный serialVersionUID для восстановления состояния сериализованного объекта и создает исключение java.io.InvalidClassException в случае несовпадения serialVersionUID
Читать подробнее: http://javarevisited.blogspot.com/2011/04/top-10-java-serialization-interview.html
Было бы неплохо, если бы CheckStyle мог проверить, что serialVersionUID в классе, который реализует Serializable, имеет хорошее значение, то есть соответствует тому, что будет генерировать генератор идентификатора последовательной версии. Если у вас есть проект с большим количеством сериализуемых DTO, например, не забудьте удалить существующий serialVersionUID и восстановить его, это боль, и в настоящее время единственный (который я знаю) способ проверить это состоит в том, чтобы восстановить для каждого класса и сравнить с Старый. Это очень очень больно.
Если вы хотите изменить огромное количество классов, для которых в первую очередь не был установлен 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
Этот скрипт использует инструмент JDK serialVer под капотом. Поэтому убедитесь, что ваш $JAVA_HOME/bin находится в PATH.
Этот вопрос очень хорошо задокументирован в книге "Эффективная Java" Джошуа Блоха. Очень хорошая книга, которую нужно прочитать. Я изложу некоторые из причин ниже:
Среда выполнения сериализации предлагает номер, называемый последовательной версией, для каждого сериализуемого класса. Этот номер называется serialVersionUID. Теперь за этим числом стоит некоторая математика, и она основана на полях / методах, определенных в классе. Для одного и того же класса каждый раз генерируется одна и та же версия. Этот номер используется во время десериализации для проверки того, что отправитель и получатель сериализованного объекта загрузили классы для этого объекта, которые совместимы в отношении сериализации. Если получатель загрузил класс для объекта, который имеет serialVersionUID, отличный от класса соответствующего отправителя, то десериализация приведет к исключению InvalidClassException.
Если класс является сериализуемым, вы также можете явно объявить свой собственный serialVersionUID, объявив поле с именем "serialVersionUID", которое должно быть статическим, конечным и иметь тип long. Большинство IDE, таких как Eclipse, помогают вам генерировать эту длинную строку.
Каждый раз, когда объект сериализуется, объект помечается идентификатором версии для класса объекта. Этот идентификатор называется serialVersionUID и вычисляется на основе информации о структуре класса. Предположим, что вы создали класс Employee, и у него есть идентификатор версии #333 (назначенный JVM). Теперь, когда вы будете сериализовать объект этого класса (предположим, объект Employee), JVM назначит ему UID как #333.
Рассмотрим ситуацию - в будущем вам нужно отредактировать или изменить свой класс, и в этом случае, когда вы его измените, JVM назначит ему новый UID (предположим, #444). Теперь, когда вы попытаетесь десериализовать объект employee, JVM сравнит идентификатор версии сериализованного объекта (объекта Employee) (#333) с идентификатором класса, т. Е. #444(поскольку он был изменен). При сравнении JVM обнаружит, что обе версии UID различаются, и, следовательно, десериализация не удастся. Следовательно, если serialVersionID для каждого класса определяется самим программистом. Это будет то же самое, даже если класс будет развиваться в будущем, и, следовательно, JVM всегда обнаружит, что класс совместим с сериализованным объектом, даже если этот класс изменен. Для получения дополнительной информации вы можете обратиться к главе 14 HEAD FIRST JAVA.
Простое объяснение
1. Сериализуете ли вы данные? Сериализация - это запись данных класса в файл / поток / и т. Д. Десериализация читает эти данные обратно в класс.
2. Собираетесь ли вы пойти в производство? Если вы просто тестируете что-то с неважными / поддельными данными, не беспокойтесь об этом (если только вы не тестируете сериализацию напрямую).
3. Это первая версия? Если так, установите serialVersionUID=1L
,
4. Это вторая, третья и т. Д. Версия? Теперь вам нужно беспокоиться о serialVersionUID
, и должны изучить это в глубине.
По сути, если вы не обновите версию правильно, когда вы обновляете класс, который вам нужен для записи / чтения, вы получите сообщение об ошибке при попытке прочитать старые данные.
Короче говоря, это поле используется для проверки правильности десериализации сериализованных данных. Сериализация и десериализация часто выполняются разными копиями программы - например, сервер преобразует объект в строку, а клиент преобразует полученную строку в объект. Это поле говорит о том, что оба оперируют одинаковыми представлениями о том, что это за объект. Это поле помогает, когда:
у вас есть много разных копий вашей программы в разных местах (например, 1 сервер и 100 клиентов). Если вы измените свой объект, измените свой номер версии и забудете обновить один из этих клиентов, он будет знать, что он не способен к десериализации
вы сохранили свои данные в каком-то файле, и позже вы попытаетесь открыть их с обновленной версией вашей программы с измененным объектом - вы будете знать, что этот файл несовместим, если вы сохраните правильную версию
Когда это важно?
Наиболее очевидно - если вы добавите некоторые поля к вашему объекту, более старые версии не смогут использовать их, потому что у них нет этих полей в их объектной структуре.
Менее очевидно - при десериализации объекта поля, которые не представлены в строке, будут сохранены как NULL. Если вы удалили поле из вашего объекта, более старые версии будут сохранять это поле как всегда-NULL, что может привести к неправильному поведению, если более старые версии полагаются на данные в этом поле (в любом случае вы создали его для чего-то, а не просто для удовольствия:-))
Наименее очевидный - иногда вы меняете идею, которую вы вкладываете в значение некоторой области. Например, когда вам 12 лет, вы подразумеваете "велосипед" под словом "велосипед", но когда вам 18 лет, вы имеете в виду "мотоцикл" - если ваши друзья пригласят вас на "поездку на велосипеде по городу", и вы будете единственным, кто приехал на велосипеде, вы поймете, как важно сохранять одинаковое значение в разных областях:-)
Serial VersionUID - это 64-битное число, используемое для уникальной идентификации класса во время процесса десериализации. При сериализации объекта serialVersionUID класса также записывается в файл. Всякий раз, когда вы десериализуете этот объект, среда выполнения java извлекает это значение serialVersionUID из сериализованных данных и сравнивает то же значение, связанное с классом. Если оба не совпадают, будет выбрано исключение java.io.InvalidClassException.
Если сериализуемый класс явно не объявляет serialVersionUID, то среда выполнения сериализации вычислит значение serialVersionUID для этого класса на основе различных аспектов класса, таких как поля, методы и т. Д., Вы можете сослаться на эту ссылку для демонстрационного приложения.
Во-первых, чтобы ответить на ваш вопрос, когда мы не объявляем SerialVersionUID в нашем классе, среда выполнения Java генерирует его для нас, но этот процесс чувствителен ко многим метаданным класса, включая количество полей, тип полей, модификатор доступа к полям, реализованный интерфейс по классам и т. д. Поэтому рекомендуется объявить это самим, и Eclipse предупреждает вас об этом.
Сериализация: мы часто работаем с важными объектами, состояние которых (данные в переменных объекта) настолько важно, что мы не можем рискнуть потерять их из-за сбоев питания / системы (или) сбоев сети в случае отправки состояния объекта другому машина. Решение этой проблемы называется "Постоянство", что просто означает сохранение (хранение / сохранение) данных. Сериализация является одним из многих других способов достижения постоянства (путем сохранения данных на диск / в память). При сохранении состояния объекта важно создать идентичность для объекта, чтобы иметь возможность правильно прочитать его обратно (десериализация). Этот уникальный идентификатор ID является SerialVersionUID.
Что такое SerialVersionUID? Ответ: - Допустим, есть два человека, один из HQ, а другой из ODC, оба будут выполнять сериализацию и десериализацию соответственно. В этом случае, чтобы подтвердить, что получатель, находящийся в ODC, является аутентифицированным лицом, JVM создает уникальный идентификатор, который известен как SerialVersionUID.
Вот хорошее объяснение, основанное на сценарии,
Почему именно SerialVersionUID?
Сериализация: во время сериализации JVM на стороне отправителя каждого объекта сохраняет уникальный идентификатор. JVM отвечает за создание этого уникального идентификатора на основе соответствующего файла.class, который присутствует в системе отправителя.
Десериализация: во время десериализации JVM на стороне получателя будет сравнивать уникальный идентификатор, связанный с объектом, с уникальным идентификатором локального класса, т.е. JVM также создаст уникальный идентификатор на основе соответствующего файла.class, который присутствует в системе получателя. Если оба уникальных идентификатора совпадают, будет выполнена только десериализация. В противном случае мы получим исключение времени выполнения с сообщением InvalidClassException. Этот уникальный идентификатор - не что иное, как SerialVersionUID.