Java对象的serialVersionUID在序列化和反序列化的用途
来源:互联网 发布:sql msde 编辑:程序博客网 时间:2024/06/05 15:40
本博客主要转自如下链接
http://blog.csdn.net/javazejian/article/details/52665164
这篇文章写的不错,但是有些地方我估计博主没有亲自测试,所以有些地方我亲测后发现其实他说的不对,大家可以先看看他写的,然后再看看我下面说的具体哪里不对了
先说说serialVersionUID的用途:
其实一个类要实现序列化和反序列化,不声明serialVersionUID是可行的,serialVersionUID主要是辅助序列化和反序列化,序列化和反序列化的时候,serialVersionUID必须一致,反序列化才会成功。具体的序列化过程是这样的:序列化操作的时候系统会把当前类的serialVersionUID写入到序列化文件中,当反序列化时系统会去检测文件中的serialVersionUID,判断它是否与当前类的serialVersionUID一致,如果一致就说明序列化类的版本与当前类版本是一样的,可以反序列化成功,否则失败。报出如下UID错误:
Exception in thread "main" java.io.InvalidClassException: com.zejian.test.Client; local class incompatible: stream classdesc serialVersionUID = -2083503801443301445, local class serialVersionUID = -4083503801443301445
原博文中主要错在这句话 “因此强烈建议指定serialVersionUID,这样的话即使微小的变化也不会导致crash的出现,如果不指定的话只要这个文件多一个空格,系统自动生成的UID就会截然不同的,反序列化也就会失败“
亲测发现,当不指定serialVersionUID的时候,将对象序列化到文件中后,如果仅仅在对象文件中添加了一些空格或者换行,反序列化仍然会成功,而并不是那篇博客中说的加个空格就会反序列化失败。原因应该是serialVersionUID的生成方法是基于对象的一些属性生成的,而跟这个对象文件中的空格换行等是没有关系的。
我试着在没有指定的serialVersionUID的情况下,序列化后,在对象中添加了一个属性,并对之前生成的序列化后的文件进行反序列化,发现失败了,抛了上述说的异常,这是因为在对象中添加了属性后,由于没有指定serialVersionUID,所以系统会自动根据这个对象的属性等产生一个新的serialVersionUID,这就导致这个serialVersionUID与序列化文件中的serialVersionUID不一致,从而反序列化失败。
接着,我为对象加了serialVersionUID属性,在intellij idea中为一个对象加serialVersionUID的方法如下:
Setting->Inspections->Serialization issues->Serializable class without ’serialVersionUID’
选中以上后,在你的class中:光标定位在类名前,按 Alt+Enter 就会提示自动创建 serialVersionUID 了。在添加了serialVersionUID的对象中,我重新进行了序列化,序列化后,我在对象中添加了一个新的属性,也修改了原有的属性,但是serialVersionUID没有变,所以序列化文件中的serialVersionUID和对象文件中的serialVersionUID一致,反序列化都成功,但是只会反序列化成功匹配上的属性值,没有匹配上的都会为null。如果在序列化后修改了serialVersionUID的值,则反序列化会失败,抛出上述异常。
下面是上述博客中测试的例子,我进行了点修改方便测试:
被序列化对象Client:注意,这个对象中的几个object相关方法是用来自定义序列化和反序列化过程的,我们自定义哪些属性需要序列化,上述测试我把object相关方法都注释掉了。
package com.sogou.study.serialize;/** * Created by denglinjie on 2016/9/29. */import java.io.IOException;import java.io.ObjectStreamException;import java.io.Serializable;public class Client implements Serializable{ /** * 生成序列号标识 */ private static final long serialVersionUID = -2083503801443301445L; private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } /** * 序列化时, * 首先系统会先调用writeReplace方法,在这个阶段, * 可以进行自己操作,将需要进行序列化的对象换成我们指定的对象. * 一般很少重写该方法 * @return * @throws ObjectStreamException */ private Object writeReplace() throws ObjectStreamException { System.out.println("writeReplace invoked"); return this; } /** *接着系统将调用writeObject方法, * 来将对象中的属性一个个进行序列化, * 我们可以在这个方法中控制住哪些属性需要序列化. * 这里只序列化name属性 * @param out * @throws IOException */ private void writeObject(java.io.ObjectOutputStream out) throws IOException { System.out.println("writeObject invoked"); //这里自定义只序列化了对象的name属性到文件中 out.writeObject(this.name == null ? "zejian" : this.name); } /** * 反序列化时,系统会调用readObject方法,将我们刚刚在writeObject方法序列化好的属性, * 反序列化回来.然后通过readResolve方法,我们也可以指定系统返回给我们特定的对象 * 可以不是writeReplace序列化时的对象,可以指定其他对象. * @param in * @throws IOException * @throws ClassNotFoundException */ private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { System.out.println("readObject invoked"); //由于序列化的时候自定义只序列化了name属性,所以这里读出来的object就是name的值,可以直接转换成String this.name = (String) in.readObject(); System.out.println("got name:" + name); } /** * 通过readResolve方法,我们也可以指定系统返回给我们特定的对象 * 可以不是writeReplace序列化时的对象,可以指定其他对象. * 一般很少重写该方法 * @return * @throws ObjectStreamException */ private Object readResolve() throws ObjectStreamException { System.out.println("readResolve invoked"); return this; }}
序列化类
package com.sogou.study.serialize;/** * Created by denglinjie on 2016/9/29. */import java.io.FileOutputStream;import java.io.ObjectOutputStream;public class SerializeTest { public static void main(String[] args) throws Exception { //把对象序列化到文件 Client client = new Client(); client.setId(11); client.setName("client"); ObjectOutputStream oo = new ObjectOutputStream (new FileOutputStream("D:\\test\\file1.txt")); oo.writeObject(client); oo.close(); }}
反序列化类:
package com.sogou.study.serialize;/** * Created by denglinjie on 2016/9/29. */import java.io.FileInputStream;import java.io.ObjectInputStream;public class UnSerializeTest { public static void main(String[] args) throws Exception { //反序列化到内存 ObjectInputStream oi = new ObjectInputStream (new FileInputStream("D:\\test\\file1.txt")); Client c_back = (Client) oi.readObject(); System.out.println(c_back.getName()); System.out.println(c_back.getId()); oi.close(); }}
- Java对象的serialVersionUID在序列化和反序列化的用途
- serialVersionUID的作用、java的序列化/反序列化
- Java Serializable序列化,反序列化 ,serialVersionUID的作用
- serialVersionUID序列化和反序列化的概念
- 【Java SE】对象的序列化与反序列化3:SerialversionUID
- java序列化和反序列化以及serialVersionUID的作用
- java对象的序列化和反序列化
- Java对象的序列化和反序列化
- Java对象的序列化和反序列化
- Java对象的序列化和反序列化实践
- Java对象的序列化和反序列化
- Java对象的序列化和反序列化
- Java对象的序列化和反序列化实践
- Java对象的序列化和反序列化实践
- Java对象的序列化和反序列化实践
- java对象的序列化和反序列化
- [Java] 对象的序列化和反序列化
- java对象的序列化和反序列化
- Markdown语法
- javascript 函数
- 打造自己的php框架
- IO多路复用实践
- 学习封装 MVC (1)
- Java对象的serialVersionUID在序列化和反序列化的用途
- git常用命令---逐渐补充完善
- struts2的配置和一个简单的例子
- C++经典面试题
- P问题,NP问题,NPC问题概念
- 编程之美 - 最大子数组和
- 轻量方便美观的log工具
- MVC的搭建过程
- linux中单独的test.sh可以执行,将test.sh加入cron定时任务却执行不成功(echo 导致)