Понять serialVersionUID

Понять serialVersionUID

Если вы когда-либо реализовывали интерфейсSerializable, вы должны столкнуться с этим предупреждающим сообщением

The serializable class xxx does not declare a static final serialVersionUID field of type long

Итак ... что такое serialVersionUID?

SerialVersionUID используется в качестве элемента управления версиями в классе Serializable. Если вы явно не объявляете serialVersionUID, JVM сделает это за вас автоматически на основе различных аспектов вашего класса Serializable, как описано вJava™ Object Serialization Specification.

1. Пример SerialVersionUID

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

1.1 Address.java

Сериализуемый класс с serialVersionUID 1L.

import java.io.Serializable;

public class Address implements Serializable{

       private static final long serialVersionUID = 1L;

       String street;
       String country;

       public void setStreet(String street){
           this.street = street;
       }

       public void setCountry(String country){
           this.country = country;
       }

       public String getStreet(){
           return this.street;
       }

       public String getCountry(){
           return this.country;
       }

       @Override
       public String toString() {
           return new StringBuffer(" Street : ")
           .append(this.street)
           .append(" Country : ")
           .append(this.country).toString();
       }
}

1.2 WriteObject.java

Простой класс для записи / сериализации объекта Address в файл - «c: \ address.ser».

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

public class WriteObject{

    public static void main (String args[]) {

       Address address = new Address();
       address.setStreet("wall street");
       address.setCountry("united states");

       try{

        FileOutputStream fout = new FileOutputStream("c:\\address.ser");
        ObjectOutputStream oos = new ObjectOutputStream(fout);
        oos.writeObject(address);
        oos.close();
        System.out.println("Done");

       }catch(Exception ex){
           ex.printStackTrace();
       }
    }
}

1.3 ReadObject.java

Простой класс для чтения / десериализации объекта Address из файла - «c: \ address.ser».

import java.io.FileInputStream;
import java.io.ObjectInputStream;

public class ReadObject{

   public static void main (String args[]) {

       Address address;

       try{

           FileInputStream fin = new FileInputStream("c:\\address.ser");
           ObjectInputStream ois = new ObjectInputStream(fin);
           address = (Address) ois.readObject();
           ois.close();

           System.out.println(address);

       }catch(Exception ex){
           ex.printStackTrace();
       }
   }
}

2. тестирование

Давайте проведем некоторое тестирование, чтобы продемонстрировать использование serialVersionUID.

2.1 Same serialVersionUID

Тот же serialVersionUID, во время процесса десериализации проблем нет

javac Address.java
javac WriteObject.java
javac ReadObject.java
java WriteObject
java ReadObject
Street : wall street Country : united states

2.2 Different serialVersionUID

В Address.java,change the serialVersionUID to 2L (это был 1L), и скомпилируйте его снова.

javac Address.java
java ReadObject
java.io.InvalidClassException: Address; local class incompatible:
stream classdesc serialVersionUID = 1, local class serialVersionUID = 2
        ...
        at ReadObject.main(ReadObject.java:14)

«InvalidClassException» будет повышаться, потому что вы пишете класс сериализации сserialVersionUID “1L”, но пытаетесь получить его обратно с обновленным классом сериализацииserialVersionUID “2L”.

SerialVersionUID должен совпадать в процессе сериализации и десериализации.

When should update your serialVersionUID?
Когда ваш класс сериализации обновляется с некоторыми несовместимыми изменениями типа Java в сериализуемом классе, вам необходимо обновить свой serialVersionUID.

Подробные сведения о совместимых и несовместимых изменениях типа Java в сериализуемом классе см. ВJava Object Serialization Specification.

3. Что не так со стандартным serialVersionUID?

Если serialVersionUID не объявлен, JVM будет использовать свой собственный алгоритм для генерации SerialVersionUID по умолчанию, вы можете проверить алгоритмhere.

The default serialVersionUID computation is highly sensitive to class details and may vary from different JVM implementation и приводят к непредвиденным исключениям InvalidClassExceptions во время процесса десериализации.

3.1 Client / Server environment

- Клиент использует JVM SUN в Windows.
- Сервер использует JRockit в Linux.

Клиент отправляет сериализуемый класс со сгенерированным по умолчанию serialVersionUID (например, 123L) на сервер через сокет, сервер может генерировать другой serialVersionUID (например, 124L) во время процесса десериализации и вызывает неожиданные исключения InvalidClassExceptions.

3.2 File / Database environment

- Приложение №1 использует JVM SUN в Windows.
- Приложение №2 использует JRockit в Linux.

Сериализация позволила сохранить в файл или базу данных. Приложение № 1 сохраняет сериализуемый класс в базе данных по умолчанию, сгенерированный serialVersionUID (например, 123L), в то время как Приложение № 2 может генерировать другой serialVersionUID (например, 124L) в процессе десериализации и вызывать неожиданные исключения InvalidClassExceptions.

Вы можете проверить здесьList of the JVM implementation.

4. Как сгенерировать serialVersionUID

Вы можете использовать JDK «serialver» или Eclipse IDE для автоматической генерации serialVersionUID,see detail.

Заключение

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