Understand the serialVersionUID

来源:互联网 发布:mysql 开放远程访问 编辑:程序博客网 时间:2024/06/08 18:43

大致翻译自Understand the serialVersionUID

Understand the serialVersionUID

如果你曾经实现过Serializable接口,你肯定遇到过如下的警告信息

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

So…what is serialVersionUID?

在一个Serializable类中,serialVersionUID被用来做版本控制。如果你不显式声明一个serialVersionUID,JVM会基于你的Serializable类的各个方面,自动为你生成。参见Java(TM) Object Serialization Specification

1. SerialVersionUID例子

上面的说明在开始时可能有点难以理解(至少我是这样的),让我们开始用一个例子来了解Serializable类,以及如何使用SerialVersionUID实现版本控制。

1.1 Address.java

一个serialVersionUID1L的序列化类

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

一个简单的类从文件c:\\address.ser读取/反序列化Address对象

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. Testing

做一些测试来演示serialVersionUID的使用

2.1 同样的serialVersionUID

同样的serialVersionUID,在反序列化的过程中是没有问题的

javac Address.javajavac WriteObject.javajavac ReadObject.javajava WriteObjectjava ReadObjectStreet : wall street Country : united states

2.2 不同的serialVersionUID

在Address.java中,把serialVersionUID改变为 2L(原来为1L),再次编译:

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

会抛出InvalidClassException异常,因为你写的序列化类serialVersionUID1L,却尝试使用更新的序列化类SerialVersionUID2L来检索它

serialVersionUID在序列化和反序列化过程中必须匹配。

什么时候应该更新你的serialVersionUID?
当序列化类中有一些不兼容的Java类型改变时,序列化被改变,必须更新serialVersionUID。(When your serialization class is updated with some incompatible Java type changes to a serializable class, you have to update your serialVersionUID.)
有关可序列化类的兼容和不兼容的Java类型更改的详细信息,请参阅Java对象序列化规范。

3. 缺省的serialVersionUID是怎么回事?

如果没有声明serialVersionUID,JVM将使用自己的算法来生成一个默认的SerialVersionUID,你可以在这里检查算法。

缺省的serialVersionUID计算对类详细信息非常敏感,并且可能因不同的JVM实现而异,并在反序列化过程中导致意外的InvalidClassExceptions

3.1 Client / Server 环境

  • 在Windows中,客户端正中使用SUN的JVM。
  • 在Linux中,服务器使用JRockit。

客户端通过socket将具有默认生成的serialVersionUID(例如123L)的可序列化类发送到服务器,服务器可能在反序列化过程中生成不同的serialVersionUID(例如124L),并抛出异常InvalidClassExceptions

3.2 File / Database 环境

  • 在Windows中,应用#1使用SUN的JVM。
  • 在Linux中,应用#2使用JRockit。

序列化可被保存到文件或数据库中。某些情况下,应用#1将默认生成的serialVersionUID(例如123L)序列化类存储到数据库中,而在编译过程中,App#2可能会生成不同的serialVersionUID(例如124L),并抛出异常InvalidClassExceptions

你可以在此处查看JVM实现列表

4. 如何产生serialVersionUID

可以使用JDK serialver 或Eclipse IDE自动生成serialVersionUID,详细信息。

总结

SUN是强烈建议开发人员声明serialVersionUID以避免上面列出的不同的JVM问题,但是我建议你理解什么是序列化,serialVersionUID如何实现版本控制以及为什么你的类需要使用序列化。了解serialVersionUID的概念比任何建议更好。


序列化

对象序列化(object serialization)API,它提供了一个框架,用来将对象编码成字节流,并从字节流编码中重新构建对象。
将一个对象编码成一个字节流,称作该对象序列化(serializing),想反的处理过程被称为反序列化(deserializing)