Что такое serialVersionUID и почему я должен его использовать?

StackOverflow https://stackoverflow.com/questions/285793

Вопрос

Eclipse выдает предупреждения, когда serialVersionUID отсутствует.

Сериализуемый класс Foo не объявляет статическое конечное поле serialVersionUID типа long

Что такое serialVersionUID и почему это так важно?Пожалуйста, покажите пример, где отсутствует serialVersionUID это вызовет проблему.

Это было полезно?

Решение

Документы для 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 по возможности использовали закрытый модификатор, поскольку такие объявления применяются только к непосредственно объявленным полям класса serialVersionUID и не используются как унаследованные члены.

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

Если вы сериализуете только потому, что вам нужно сериализовать ради реализации (кого волнует, например, если вы сериализуете для HTTPSession ... если он сохранен или нет, вы, вероятно, не не заботьтесь о десериализации объекта формы), тогда вы можете проигнорировать это.

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

В большинстве случаев вы, вероятно, не будете использовать сериализацию напрямую. В этом случае создайте SerialVersionUID по умолчанию, щелкнув параметр быстрого исправления, и не беспокойтесь об этом.

Я не могу упустить эту возможность, чтобы подключить книгу Джоша Блоха Эффективная Java (2-е издание). Глава 11 является необходимым ресурсом по сериализации Java.

Согласно Джошу, автоматически сгенерированный UID генерируется на основе имени класса, реализованных интерфейсов и всех открытых и защищенных членов. Любое изменение любого из них изменит serialVersionUID . Поэтому вам не нужно связываться с ними, только если вы уверены, что не более одной версии класса никогда не будет сериализовано (либо между процессами, либо получено из хранилища позднее).

Если вы сейчас их игнорируете и позже обнаружите, что вам нужно каким-то образом изменить класс, но сохранить совместимость со старой версией класса, вы можете использовать инструмент serialver JDK для генерации serialVersionUID в классе old и явно установите его в новом классе. (В зависимости от ваших изменений вам может потребоваться также реализовать пользовательскую сериализацию, добавив методы writeObject и readObject - см. Javadoc Serializable или вышеупомянутую главу 11.)

Вы можете сказать Eclipse игнорировать эти предупреждения serialVersionUID:

Окно > Настройки > Java > Компилятор > Ошибки / Предупреждения > Потенциальные проблемы с программированием

На случай, если вы не знали, в этом разделе есть множество других предупреждений, которые вы можете включить (или даже сообщить о некоторых как об ошибках), многие из них очень полезны:

  • Потенциальные проблемы с программированием:Возможное случайное логическое присвоение
  • Потенциальные проблемы с программированием:Доступ к нулевому указателю
  • Ненужный код:Локальная переменная никогда не читается
  • Ненужный код:Избыточная проверка нуля
  • Ненужный код:Ненужное приведение или "instanceof"

и многое другое.

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

Если вы хотите изменить версию своих данных, обычно вы начинаете с serialVersionUID равный 0, и увеличивайте его при каждом структурном изменении вашего класса, которое изменяет сериализованные данные (добавляя или удаляя непереходящие поля).

Встроенный механизм десериализации (in.defaultReadObject()) откажется от десериализации старых версий данных.Но если вы хотите, вы можете определить свой собственный readObject() Читать объект()-функция, которая может считывать старые данные.Затем этот пользовательский код может проверить serialVersionUID чтобы узнать, в какой версии находятся данные, и решить, как их десериализовать.Этот метод управления версиями полезен, если вы храните сериализованные данные, которые выдерживают несколько версий вашего кода.

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

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

Если вы забудете обновить поле, в итоге вы можете получить две разные версии класса с разной структурой, но с одинаковым serialVersionUID.Если это произойдет, механизм по умолчанию (in.defaultReadObject()) не обнаружит никакой разницы и попытается десериализовать несовместимые данные.Теперь вы можете столкнуться с загадочной ошибкой времени выполнения или тихим сбоем (нулевые поля).Ошибки такого типа могут быть труднодоступны.

Таким образом, чтобы облегчить это использование, платформа Java предлагает вам на выбор не устанавливать serialVersionUID вручную.Вместо этого хэш структуры класса будет сгенерирован во время компиляции и использован в качестве идентификатора.Этот механизм гарантирует, что у вас никогда не будет разных структур классов с одинаковым идентификатором, и поэтому вы не получите этих трудно отслеживаемых сбоев сериализации во время выполнения, упомянутых выше.

Но у стратегии автоматически генерируемого идентификатора есть обратная сторона.А именно, что сгенерированные идентификаторы для одного и того же класса могут отличаться в разных компиляторах (как упоминал Джон Скит выше).Поэтому, если вы передаете сериализованные данные между кодом, скомпилированным с помощью разных компиляторов, рекомендуется в любом случае сохранять идентификаторы вручную.

И если вы обратно совместимы со своими данными, как в первом упомянутом примере использования, вы также, вероятно, захотите сохранить идентификатор самостоятельно.Это делается для того, чтобы получить читаемые идентификаторы и иметь больший контроль над тем, когда и как они меняются.

  

Что такое serialVersionUID и почему я должен его использовать?

SerialVersionUID является уникальным идентификатором для каждого класса, JVM использует его для сравнения версий класса, обеспечивающих загрузку одного и того же класса во время сериализации при загрузке при десериализации.

Указание одного дает больше контроля, хотя JVM генерирует его, если вы не укажете. Сгенерированное значение может отличаться для разных компиляторов. Кроме того, иногда вы просто хотите по какой-то причине запретить десериализацию старых сериализованных объектов [ обратная несовместимость ], и в этом случае вам просто нужно изменить serialVersionUID.

javadocs для Serializable скажем :

  

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

Поэтому вы должны объявить serialVersionUID, поскольку он дает нам больше контроля .

В этой статье есть несколько полезных моментов по этой теме.

В первоначальном вопросе спрашивалось «почему это важно» и «пример», где этот серийный идентификатор версии был бы полезен. Ну, я нашел один.

Допустим, вы создали класс Car , создали его экземпляр и записали его в поток объектов. Расплющенный объект автомобиля некоторое время находится в файловой системе. Между тем, если класс Car изменяется, добавляя новое поле. Позже, когда вы попытаетесь прочитать (т.е. десериализовать) уплощенный объект Car , вы получите java.io.InvalidClassException & # 8211; потому что все сериализуемые классы автоматически получают уникальный идентификатор. Это исключение выдается, когда идентификатор класса не равен идентификатору сплющенного объекта. Если вы действительно думаете об этом, исключение выдается из-за добавления нового поля. Вы можете избежать этого исключения, управляя версионированием самостоятельно, объявив явный serialVersionUID. Также есть небольшое преимущество в производительности, если явно объявить ваш serialVersionUID (потому что вычислять не нужно). Поэтому рекомендуется добавлять свой собственный serialVersionUID в свои классы Serializable, как только вы создадите их, как показано ниже:

public class Car {
    static final long serialVersionUID = 1L; //assign a long value
}

Если вам никогда не понадобится сериализовать ваши объекты в байтовый массив и отправить / сохранить их, вам не нужно об этом беспокоиться. Если вы это сделаете, то вы должны рассмотреть ваш 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 сопоставляет 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.

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

Существует несколько правил для сериализации.

  • Объект сериализуем только в том случае, если его класс или его суперкласс реализует Сериализуемый интерфейс

  • Объект является сериализуемым (сам реализует сериализуемый интерфейс), даже если его суперкласс таковым не является.Однако первый суперкласс в иерархии сериализуемого класса, который не реализует сериализуемый интерфейс, ДОЛЖЕН иметь конструктор без аргументов.Если это будет нарушено, readObject() создаст исключение java.io.InvalidClassException во время выполнения

  • Все примитивные типы сериализуемы.

  • Временные поля (с модификатором transient) НЕ сериализуются (т.е. не сохраняются и не восстанавливаются).Класс, реализующий Serializable, должен отмечать переходные поля классов, которые не поддерживают сериализацию (например, файловый поток).

  • Статические поля (со статическим модификатором) не сериализуются.

Когда объект сериализуется, среда выполнения JAVA связывает серийный номер версии, который называется 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)

Не беспокойтесь, расчет по умолчанию действительно хорош и достаточен для 99,9999% случаев. И если у вас возникнут проблемы, вы можете - как уже говорилось - вводить UID как необходимость (что весьма маловероятно)

Как в примере, где отсутствующий serialVersionUID может вызвать проблему:

Я работаю над этим приложением Java EE, которое состоит из веб-модуля, который использует модуль EJB . Веб-модуль вызывает модуль EJB удаленно и передает в качестве аргумента POJO , который реализует Serializable .

Этот класс POJO был упакован внутри файла 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

Обычно я использую serialVersionUID в одном контексте: когда я знаю, что он покидает контекст Java VM.

Я знаю об этом, когда я буду использовать ObjectInputStream и ObjectOutputStream для моего приложения или если я знаю, что библиотека / инфраструктура, которую я использую, будет использовать ее. SerialVersionID гарантирует, что разные виртуальные машины Java разных версий или поставщиков будут правильно взаимодействовать, или, если он хранится и извлекается вне виртуальной машины, например, HttpSession , данные сеанса могут остаться даже во время перезапуска и обновления приложения. сервер.

Для всех остальных случаев я использую

@SuppressWarnings("serial")

, так как в большинстве случаев достаточно serialVersionUID по умолчанию. Это включает в себя Исключение , HttpServlet .

Данные поля представляют некоторую информацию, хранящуюся в классе. Класс реализует интерфейс Serializable , поэтому eclipse автоматически предложила объявить поле serialVersionUID . Давайте начнем со значения 1, установленного там.

Если вы не хотите, чтобы появилось это предупреждение, используйте это:

@SuppressWarnings("serial")

SerialVersionUID используется для контроля версий объекта. вы также можете указать serialVersionUID в вашем файле класса. Следствием отсутствия указания serialVersionUID является то, что при добавлении или изменении какого-либо поля в классе уже сериализованный класс не сможет восстановиться, поскольку serialVersionUID, сгенерированный для нового класса и для старого сериализованного объекта, будет отличаться. Процесс сериализации Java использует правильный serialVersionUID для восстановления состояния сериализованного объекта и создает исключение java.io.InvalidClassException в случае несовпадения serialVersionUID

Подробнее: http://javarevisited.blogspot.com/ 2011/04 / топ-10-Java-сериализации-interview.html # ixzz3VQxnpOPZ

Было бы неплохо, если бы CheckStyle мог проверить, что serialVersionUID в классе, который реализует Serializable, имеет хорошее значение, то есть соответствует тому, что будет генерировать генератор идентификатора последовательной версии. Если у вас есть проект с большим количеством сериализуемых DTO, например, не забудьте удалить существующий serialVersionUID и восстановить его, это боль, и в настоящее время единственный (который я знаю) способ проверить это - восстановить для каждого класса и сравнить с Старый. Это очень очень больно.

Зачем использовать SerialVersionUID внутри класса Serializable в Java?

Во время сериализации среда выполнения Java создает номер версии для класса, чтобы он мог десериализовать его позже. Этот номер версии известен как SerialVersionUID в Java.

SerialVersionUID используется для создания версий сериализованных данных. Десериализовать класс можно только в том случае, если его SerialVersionUID соответствует сериализованному экземпляру. Когда мы не объявляем SerialVersionUID в нашем классе, среда выполнения Java генерирует его для нас, но это не рекомендуется. Рекомендуется объявлять SerialVersionUID как закрытую статическую переменную final long , чтобы избежать механизма по умолчанию.

Когда вы объявляете класс как Serializable , реализуя интерфейс маркера java.io.Serializable , среда выполнения Java сохраняет экземпляр этого класса на диск с использованием механизма сериализации по умолчанию, предоставленного вы не настроили процесс, используя интерфейс Externalizable .

см. также Зачем использовать SerialVersionUID внутри класса Serializable в Java

Код: javassist.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 

Если вы хотите изменить огромное количество классов, для которых не был установлен serialVersionUID, в первую очередь, при сохранении совместимости со старыми классами, инструменты, такие как IntelliJ Idea, Eclipse, не дотягивают, так как они генерируют случайные числа и не работают на куча файлов за один раз. Я подошел к следующему сценарию bash (извините за пользователей Windows, подумайте о покупке Mac или о переходе на Linux), чтобы легко исправить проблему serialVersionUID:

add_serialVersionUID.sh < myJavaToAmend.lst

вы сохраняете этот скрипт, скажем add_serialVersionUID.sh вам ~ / bin. Затем вы запускаете его в корневом каталоге вашего проекта Maven или Gradle, например:

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

Этот .lst включает список файлов Java для добавления serialVersionUID в следующем формате:

<*>

Этот скрипт использует инструмент JDK serialVer под капотом. Поэтому убедитесь, что ваш $ JAVA_HOME / bin находится в PATH.

; printf qq{%s\n}, q{ private $seruidstr} if /public class/" $src_dir/$f done

вы сохраняете этот скрипт, скажем add_serialVersionUID.sh вам ~ / bin. Затем вы запускаете его в корневом каталоге вашего проекта Maven или Gradle, например:

<*>

Этот .lst включает список файлов Java для добавления serialVersionUID в следующем формате:

<*>

Этот скрипт использует инструмент JDK serialVer под капотом. Поэтому убедитесь, что ваш $ JAVA_HOME / bin находится в PATH.

Этот вопрос очень хорошо задокументирован в книге «Эффективная Java» Джошуа Блоха. Очень хорошая книга, которую нужно прочитать. Я изложу некоторые из причин ниже:

Среда выполнения сериализации предлагает номер, называемый последовательной версией, для каждого сериализуемого класса. Этот номер называется serialVersionUID. Теперь за этим числом стоит некоторая математика, и она основана на полях / методах, определенных в классе. Для одного и того же класса каждый раз генерируется одна и та же версия. Этот номер используется во время десериализации для проверки того, что отправитель и получатель сериализованного объекта загрузили классы для этого объекта, которые совместимы в отношении сериализации. Если получатель загрузил класс для объекта, который имеет serialVersionUID, отличный от класса соответствующего отправителя, то десериализация приведет к исключению InvalidClassException.

Если класс сериализуем, вы также можете явно объявить свой собственный serialVersionUID, объявив поле с именем " serialVersionUID " это должно быть static, final и type long. Большинство IDE, таких как Eclipse, помогают вам генерировать эту длинную строку.

Каждый раз, когда объект сериализуется, на объекте ставится отметка с идентификатором версии для класса объекта. Этот идентификатор называется serialVersionUID и он рассчитывается на основе информации о структуре класса. Предположим, вы создали класс Employee и у него есть идентификатор версии # 333 (назначенный JVM). Теперь, когда вы будете сериализовать объект этого класса (предположим, объект Employee), JVM назначит ему UID как # 333.

Рассмотрим ситуацию - в будущем вам нужно отредактировать или изменить свой класс, и в этом случае, когда вы его измените, JVM назначит ему новый UID (предположим, # 444). Теперь, когда вы попытаетесь десериализовать объект employee, JVM сравнит идентификатор версии сериализованного объекта (объекта Employee) (# 333) с идентификатором класса i.e # 444 (поскольку он был изменен). При сравнении JVM обнаружит, что обе версии UID различаются, и, следовательно, десериализация не удастся. Следовательно, если serialVersionID для каждого класса определяется самим программистом. Это будет то же самое, даже если класс будет развиваться в будущем, и, следовательно, JVM всегда обнаружит, что класс совместим с сериализованным объектом, даже если этот класс изменен. Для получения дополнительной информации вы можете обратиться к главе 14 HEAD FIRST JAVA.

Простое объяснение:

<Ол>
  • Вы сериализуете данные?

    Сериализация - это запись данных класса в файл / поток / и т. д. Десериализация читает эти данные обратно в класс.

  • Собираетесь ли вы пойти в производство?

    Если вы просто тестируете что-то с неважными / поддельными данными, не беспокойтесь об этом (если только вы не тестируете сериализацию напрямую).

  • Это первая версия?

    Если это так, установите serialVersionUID = 1L .

  • Это вторая, третья и т. д. версия продукта?

    Теперь вам нужно позаботиться о serialVersionUID , и вам стоит углубиться в это.

  • Как правило, если вы не обновите версию правильно, когда вы обновляете класс, который вам нужен для записи / чтения, вы получите сообщение об ошибке при попытке прочитать старые данные.

    Короче говоря, это поле используется для проверки правильности десериализации сериализованных данных.Сериализация и десериализация часто выполняются разными копиями программы - например, сервер преобразует объект в строку, а клиент преобразует полученную строку в объект.Это поле сообщает, что оба оперируют одним и тем же представлением о том, что это за объект.Это поле помогает, когда:

    • у вас есть много разных копий вашей программы в разных местах (например, 1 сервер и 100 клиентов).Если вы измените свой объект, измените номер своей версии и забудете обновить один из этих клиентов, он будет знать, что он не способен к десериализации

    • вы сохранили свои данные в каком-то файле, а позже пытаетесь открыть его с помощью обновленной версии вашей программы с измененным объектом - вы узнаете, что этот файл несовместим, если сохраните правильную версию

    Когда это важно?

    Самое очевидное - если вы добавите некоторые поля к своему объекту, более старые версии не смогут их использовать, потому что у них нет этих полей в структуре объекта.

    Менее очевидно - когда вы десериализуете объект, поля, которых нет в строке, будут сохранены как NULL.Если вы удалили field из своего объекта, более старые версии сохранят это поле как allways-NULL, что может привести к неправильному поведению, если более старые версии полагаются на данные в этом поле (в любом случае, вы создали его для чего-то, а не просто для развлечения :-) )

    Наименее очевидный - Иногда вы меняете идею, которую вкладываете в значение какого-то поля.Например, когда вам 12 лет, вы подразумеваете "велосипед" под словом "байк", но когда вам 18, вы подразумеваете "мотоцикл" - если ваши друзья пригласят вас "прокатиться на велосипеде по городу", и вы будете единственным, кто приехал на велосипеде, вы поймете, насколько важно сохранять одинаковое значение во всех полях :-)

    Во-первых, чтобы ответить на ваш вопрос, когда мы не объявляем serialVersionUID в нашем классе, Java runtime генерирует его для нас, но этот процесс чувствителен ко многим метаданным класса, включая количество полей, тип полей, модификатор доступа к полям, интерфейс, реализованный классом и т.д.Поэтому рекомендуется объявить это самим, и Eclipse предупреждает вас о том же.

    Сериализация:Мы часто работаем с важными объектами, состояние которых (данные в переменных объекта) настолько важно, что мы не можем рисковать потерять его из-за сбоев питания / системы (или) сетевых сбоев в случае отправки состояния объекта на другую машину.Решение этой проблемы называется "Персистентность", что просто означает сохранение (удержание / сохранение) данных.Сериализация - это один из многих других способов достижения постоянства (путем сохранения данных на диске / в памяти).При сохранении состояния объекта важно создать идентификатор для объекта, чтобы иметь возможность корректно считывать его обратно (десериализация).Этот уникальный идентификатор называется ID is serialVersionUID.

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top