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


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

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

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


2440


источник


Ответы:


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


1871



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

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

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


411



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

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

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


255



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

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

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

  • Возможные проблемы программирования: Возможное случайное логическое назначение
  • Потенциальные проблемы программирования: нулевой указатель доступа
  • Ненужный код: Локальная переменная никогда не читается
  • Необязательный код: избыточная нулевая проверка
  • Необязательный код: ненужный листинг или «экземпляр»

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


118



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

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

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

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

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

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

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

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

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


93



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

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

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

Java-документы говорят :

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

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

Эта статья имеет некоторые хорошие моменты по этой теме.


60



Original question has asked for 'why is it important' and 'example' where this Serial Version ID would be useful. Well I have found one.

Say you create a Car class, instantiate it, and write it out to an object stream. The flattened car object sits in the file system for some time. Meanwhile, if the Car class is modified by adding a new field. Later on, when you try to read (i.e. deserialize) the flattened Car object, you get the java.io.InvalidClassException – because all serializable classes are automatically given a unique identifier. This exception is thrown when the identifier of the class is not equal to the identifier of the flattened object. If you really think about it, the exception is thrown because of the addition of the new field. You can avoid this exception being thrown by controlling the versioning yourself by declaring an explicit serialVersionUID. There is also a small performance benefit in explicitly declaring your serialVersionUID (because does not have to be calculated). So, it is best practice to add your own serialVersionUID to your Serializable classes as soon as you create them as shown below:

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

39



If you get this warning on a class you don't ever think about serializing, and that you didn't declare yourself implements Serializable, it is often because you inherited from a superclass, which implements Serializable. Often then it would be better to delegate to such a object instead of using inheritance.

So, instead of

public class MyExample extends ArrayList<String> {

    public MyExample() {
        super();
    }
    ...
}

do

public class MyExample {
    private List<String> myList;

    public MyExample() {
         this.myList = new ArrayList<String>();
    }
    ...
}

and in the relevant methods call myList.foo() instead of this.foo() (or super.foo()). (This does not fit in all cases, but still quite often.)

I often see people extending JFrame or such, when they really only need to delegate to this. (This also helps for auto-completing in a IDE, since JFrame has hundreds of methods, which you don't need when you want to call your custom ones on your class.)

One case where the warning (or the serialVersionUID) is unavoidable is when you extend from AbstractAction, normally in a anonymous class, only adding the actionPerformed-method. I think there shouldn't be a warning in this case (since you normally can't reliable serialize and deserialize such anonymous classes anyway accross different versions of your class), but I'm not sure how the compiler could recognize this.


31



If you will never need to serialize your objects to byte array and send/store them, then you don't need to worry about it. If you do, then you must consider your serialVersionUID since the deserializer of the object will match it to the version of object its classloader has. Read more about it in the Java Language Specification.


28



Don't bother, the default calculation is really good and suffice for 99,9999% of the cases. And if you run into problems, you can - as already stated - introduce UID's as the need arrise (which is highly unlikely)


17