Understand the serialVersionUID

大致翻译自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.java
javac WriteObject.java
javac ReadObject.java
java WriteObject
java ReadObject
Street : wall street Country : united states
2.2 不同的serialVersionUID

在Address.java中,把serialVersionUID改变为 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异常,因为你写的序列化类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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值