`
wezly
  • 浏览: 471752 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

序列化中serialVersionUID的使用

阅读更多

先来看一个例子: 
定义一个bean: 

Java代码 
  1. public class Serial implements Serializable {  
  2.     int id;  
  3.     String name;  
  4.     public Serial(int id, String name) {  
  5.         this.id = id;  
  6.         this.name = name;  
  7.     }  
  8.     public String toString() {  
  9.         return "DATA: " + id + " " +name;  
  10.   
  11.     }  
  12. }  

序列化操作: 
Java代码 
  1. public static void main(String[] args) {  
  2.         Serial serial=new Serial(1,"hrbeu");  
  3.         System.out.println("object serial:"+serial);   
  4.         try{  
  5.             FileOutputStream fos=new FileOutputStream("serialTest.txt");   
  6.             ObjectOutputStream oos=new ObjectOutputStream(fos);   
  7.             oos.writeObject(serial);   
  8.             oos.flush();   
  9.             oos.close();   
  10.         }catch(Exception e){  
  11.             System.out.println("Exception:"+e);   
  12.         }  
  13.     }  

反序列化操作: 
Java代码 
  1. public static void main(String[] args) {  
  2.          try{   
  3.              Serial object2;   
  4.              FileInputStream fis=new FileInputStream("serialTest.txt");   
  5.              ObjectInputStream ois=new ObjectInputStream(fis);   
  6.              object2=(Serial)ois.readObject();   
  7.              ois.close();   
  8.              System.out.println("object deserial:"+object2);   
  9.             }catch(Exception e){   
  10.                 System.out.println("Exception:"+e);   
  11.             }   
  12.     }  

运行程序,则反序列化成功。 
现在改动一下bean,在定义的bean中添加一个公有方法(非私有就可以): 
Java代码 
  1. public void todo(){}//没什么意义的方法  

接下来在老版本的序列化的结果上反序列化就会出错: 
Java代码 
  1. Exception:java.io.InvalidClassException: com.serializable.test.Serial; local class incompatible: stream classdesc serialVersionUID = 5087256472645325817, local class serialVersionUID = 6553118832574415117  

接下来在定义的bean中显示的声明UID,如下: 
Java代码 
  1. private static final long serialVersionUID = 6553118832574415117L;  

再次重新执行上面的步骤,则反序列化成功。 

引用
兼容也就是版本控制,java通过一个名为UID(stream unique identifier)来控制,这个UID是隐式的,它通过类名,方法名等诸多因素经过计算而得,理论上是一一映射的关系,也就是唯一的。如果UID不一样的话,就无法实现反序列化了,并且将会得到InvalidClassException。 

有时候你的类增加了一些无关紧要的非私有方法,而逻辑字段并不改变的时候,你希望老版本和新版本保持兼容性,则需要显式的声名UID来实现。 
以下内容来自网络: 
==================================================================== 
如何保持向上兼容性: 

      向上兼容性是指老的版本能够读取新的版本序列化的数据流。常常出现在我们的服务器的数据更新了,仍然希望老的客户端能够支持反序列化新的数据流,直到其更新到新的版本。可以说,这是半自动的事情。 

      跟一般的讲,因为在java中serialVersionUID是唯一控制着能否反序列化成功的标志,只要这个值不一样,就无法反序列化成功。但只要这个值相同,无论如何都将反序列化,在这个过程中,对于向上兼容性,新数据流中的多余的内容将会被忽略;对于向下兼容性而言,旧的数据流中所包含的所有内容都将会被恢复,新版本的类中没有涉及到的部分将保持默认值。利用这一特性,可以说,只要我们认为的保持serialVersionUID不变,向上兼容性是自动实现的。 

      当然,一但我们将新版本中的老的内容拿掉,情况就不同了,即使UID保持不变,会引发异常。正是因为这一点,我们要牢记一个类一旦实现了序列化又要保持向上下兼容性,就不可以随随便便的修改了!!! 

      测试也证明了这一点,有兴趣的读者可以自己试一试。 

如何保持向下兼容性: 

         一如上文所指出的,你会想当然的认为只要保持serialVersionUID不变,向下兼容性是自动实现的。但实际上,向下兼容要复杂一些。这是因为,我们必须要对那些没有初始化的字段负责。要保证它们能被使用。 

      所以必须要利用 
      private void readObject(java.io.ObjectInputStream in) 
      throws IOException, ClassNotFoundException{ 
         in.defaultReadObject();//先反序列化对象 
         if(ver=5552){//以前的版本5552 
             …初始化其他字段 
          }else if(ver=5550){//以前的版本5550 
            …初始化其他字段 
          }else{//太老的版本不支持 
          throw new InvalidClassException(); 
      } 

      细心的读者会注意到要保证in.defaultReadObject();能够顺利执行,就必须要求serialVersionUID保持一致,所以这里的ver不能够利用serialVersionUID了。这里的ver是一个我们预先安插好的final long ver=xxxx;并且它不能够被transient修饰。所以保持向下的兼容性至少有三点要求: 

           1.serialVersionUID保持一致 
           2.预先安插好我们自己的版本识别标志的final long ver=xxxx; 
           3.保证初始化所有的域 

讨论一下兼容性策略: 

         到这里我们可以看到要保持向下的兼容性很麻烦。而且随着版本数目的增加。维护会变得困难而繁琐。讨论什么样的程序应该使用怎么样的兼容性序列化策略已经超出本文的范畴,但是对于一个游戏的存盘功能,和对于一个字处理软件的文档的兼容性的要求肯定不同。对于rpg游戏的存盘功能,一般要求能够保持向下兼容,这里如果使用java序列化的方法,则可根据以上分析的三点进行准备。对于这样的情况使用对象序列化方法还是可以应付的。对于一个字处理软件的文档的兼容性要求颇高,一般情况下的策略都是要求良好的向下兼容性,和尽可能的向上兼容性。则一般不会使用对象序列化技术,一个精心设计的文档结构,更能解决问题。 

分享到:
评论

相关推荐

    java序列化和serialVersionUID的使用方法实例

    主要介绍了java序列化和serialVersionUID的使用方法实例的相关资料,这里说明很详细的使用方法让你彻底学会,需要的朋友可以参考下

    序列化版本号serialVersionUID的作用_动力节点Java学院整理

    序列化版本号serialVersionUID的作用_动力节点Java学院整理.

    什么是Java的序列化和反序列化?如何实现对象的序列化和反序列化?(java面试题附答案).txt

    代码中,我们定义了一个 Person 类,...需要注意的是,序列化和反序列化的类必须具有相同的 serialVersionUID,以确保对象的一致性。同时,为了避免序列化敏感信息,可以使用 transient 关键字标记不需要序列化的字段。

    java序列化实现演示

    Java序列化机制(2)- serialVersionUID 实验 http://blog.csdn.net/suileisl/article/details/16991753

    序列化和反序列化1

    序列化ID 两个类的序列化ID相同才能保证反序列的对象是一致private static final long serialVersionUID在序列化过程中,

    03-03-02-序列化和反序列化1

    1. 先将 user 对象序列化到文件中 2. 然后修改 user 对象,增加 serialVersionUID 字段 3. 然后通过反序列化来把对象提取出来

    3分钟读阿里Java手册: 序列化

    序列化:将数据对象转换为二进制的过程称之为序列化(Serialization) 反序列化:将二进制流恢复为数据对象称之为反序列化(Deserialization) 序列化方式 Java原生序列化 Java类通过实现Serializable接口实现该类对象的...

    从根上读懂阿里手册 | 为啥不能轻易修改serialVersionUID字段

    【强制】序列化类新增属性时,请不要修改 serialVersionUID 字段,避免反序列失败; 如果 完全不兼容升级,避免反序列化混乱,那么请修改 serialVersionUID 值。 说明:注意 serialVersionUID 不一致会抛出序列化...

    JAVA基础,常见java基础问题.rar

    2.接口和抽象类有什么区别 接口不能有方法实现,也就是说接口的方法都是抽象方法,但抽象类可以有方法实现。...序列化的实现一般是通过实现Serializable接口,并且会有一个serialVersionUID,这个ID叫做序列化ID

    Stephenerialization:Java 跨版本序列化问题的解决方案。-开源

    当尝试在不同版本的类之间进行... 使用静态 serialVersionUID 是一个好的开始,但还不够。 如果您想要解决 Java 序列化问题,那就别无所求! Stephenerialization 使您可以轻松地在不同版本的 Java 类之间进行序列化!

    Java关键字—-transient

    本篇文章序列化、反序列化用的类是同一个类,可以通过注释main中1然后修改Stu类实现有无transient关键字修饰、serialVersionUID是否不同,得到以下结果: 1、serialVersionUID的数值大小不会影响序列化后的字节数...

    Serializable-master.zip

    1.serialVersionUID-->适用于Java的序列化机制: 2.具体化序列化过程: 3.serialVersionUID有两种显示的生成方式:

    阿里巴巴编码规范 基础技能认证 考题分析(考题+答案).docx

    D .POJO类的serialVersionUID不一致会抛出序列化运行时异常。 多选 9.关于Java的接口描述,下列哪些说法符合《阿里巴巴Java开发手册》:BCD A .在接口类中的方法和属性使用public修饰符。 B .对于Service类,...

    ConcurrentHashMap集合源码学习笔记

    1、概念 ConcurrentHashMap继承了AbstractMap,实现了ConcurrentMap,Serializable接口,ConcurrentMap又实现了Map接口。ConcurrentHashMap是基于散列表...对象序列化的UID,类序列化时会传入一个serialVersionUID。

    findbug 常见异常处理

    描述:类是可序列化的,但是没有定义serialVersionUID; 处理方式:自动生成serialVersionUID; Field only ever set to null 描述:Field一直被设置为null; 处理方式:检查相关filed的调用情况,看所有对Field的...

    java8集合源码-Java:Java

    Java中序列化和反序列化的区别。 什么是SerialVersionUID? 内部类和子类的区别。 JSON 相对于 XML 的优势是什么? 我们可以两次导入相同的包/类吗? JVM 会在运行时加载包两次吗? 静态加载和动态类加载的区别? ...

    @SuppressWarnings

    serial 当在可序列化的类上缺少 serialVersionUID 定义时的警告。 finally 任何 finally 子句不能正常完成时的警告。 all 关于以上所有情况的警告。 @SuppressWarnings 批注允许您选择性地取消特定代码段(即,类或...

    SerialVer task for ANT-开源

    SerialVer将Java serialver功能添加到Apache-Jakarta的ANT工具中。 该项目在可序列化类的源代码中添加了Tasks和FilterReaders来获取,插入和修改serialVersionUID。

    memcached1

    我们首先把TBean的一个实例放入缓存中,然后再取出来,并进行名称的修改,然后我们再取这个对象,我们再看其名称,发现修改的对象并不是缓存中的对象,而是通过序列化过来的一个实例对象,这样我们就无须担心对原生...

Global site tag (gtag.js) - Google Analytics