java序列化的版本管理
来源:互联网 发布:saas java开源架构 编辑:程序博客网 时间:2024/04/30 20:37
本文是针对java序列化的版本管理进行阐述的,请大家先看个例子,
一个用于网络传输的实体类FInterfaceObject,程序中是这样使用的:
public class SeriaTest
{
public static void main(String[] args)
{
String fileUrl = "./example";
FInterfaceObject fIObjOutput =FInterfaceObject.staticFinalFIObj;
write(fileUrl,fIObjOutput);
FInterfaceObject obj =(FInterfaceObject)read(fileUrl);
System.out.println(obj);
}
public static void write(String fileUrl,FInterfaceObjectobj)
{
ObjectOutputStream out = null;
try
{
out = new ObjectOutputStream(newFileOutputStream(fileUrl));
out.writeObject(obj);
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
if(out != null)
{
try
{
out.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
public static FInterfaceObject read(StringfileUrl)
{
ObjectInputStream in = null;
FInterfaceObject fIObjInput = null;
try
{
in = new ObjectInputStream(newFileInputStream(fileUrl));
fIObjInput = (FInterfaceObject)in.readObject();
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
if(in != null)
{
try
{
in.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
return fIObjInput;
}
}
类FInterfaceObject的定义如下:
public class FInterfaceObjectimplements Serializable
{
public static finalFInterfaceObjectstaticFinalFIObj =newFInterfaceObject(1);
private int id = 0;
private FInterfaceObject (int value)
{
id = value;
}
public String toString()
{
return"id: "+String.valueOf(id);
}
}
此时,执行程序SeriaTest.java,输出打印信息为:id: 1
之后,由于需求变化,需要给FInterfaceObject新增个域:String name,类定义变为:
public class FInterfaceObject implements Serializable
{
public static final FInterfaceObject staticFinalFIObj = newFInterfaceObject(1);
private int id = 0;
private Stringname ="object1";
private FInterfaceObject(int value)
{
id = value;
}
public String toString()
{
return"id: "+String.valueOf(id) +"name: "+name;
}
}
此时,将程序SeriaTest.java的main()方法改为如下,只写出,且写出到example2中,后面会用到该文件,暂且放下。
public static void main(String[] args)
{
String fileUrl = "./example2";
FInterfaceObject fIObjOutput = FInterfaceObject.staticFinalFIObj;
write(fileUrl,fIObjOutput);
}
现在,再次修改程序SeriaTest.java的main()方法为只读入example文件,去掉写出的两行代码:
public static void main(String[] args)
{
String fileUrl = "./example";
FInterfaceObject obj =(FInterfaceObject)read(fileUrl);
System.out.println(obj);
}
之后执行程序SeriaTest.java,重新读入之前的输出文件example,大家猜猜会打印什么呢?下面是执行结果:
null
java.io.InvalidClassException: practice.FInterfaceObject; local class incompatible:stream classdesc serialVersionUID = 8436122587265072399, local classserialVersionUID = 2044314194551933020
at java.io.ObjectStreamClass.initNonProxy(UnknownSource)
……
为什么读出来的对象是null?这个异常又是什么意思?
原因就在于java的流机制,拒绝读入序列化版本不同的对象,异常信息表明:流读入的对象类序列化版本为8436122587265072399,而本地程序中该类的序列化版本为:2044314194551933020,两者不一致,因此流拒绝读入而抛java.io.InvalidClassException异常。抛异常后,read方法返回null,因此打印出来是null.
那如何解决这个问题呢?
为了向jvm表示,新类兼容之前版本的类,需要将之前类的序列化版本UID写入新类,做为新类的static final 域。即在类FInterfaceObject中,增加下面一行:
private static final longserialVersionUID = 8436122587265072399L;
增加这行后,再执行程序SeriaTest.java,程序输出:
id: 1 name:null.
example.txt文件中的对象是没有域name的,但java流机制可以兼容处理,对流中对象少于本地类中的属性,根据属性类型的不同,取其对应的默认值(如果是对象则是null,数字则是0,如果是boolean则是false)。若流中对象域多于本地类,则忽略这些域。
需求继续变化,又需要给类FInterfaceObject中,增加一个域:int age,类定义变为:
public class FInterfaceObject implements Serializable
{
private static final long serialVersionUID = 8436122587265072399L;
public static final FInterfaceObject staticFinalFIObj = newFInterfaceObject(1);
private int id = 0;
private Stringname ="object1";
private int age = 1;
private FInterfaceObject(int value)
{
id = value;
}
public String toString()
{
return"id:"+String.valueOf(id) +" name: "+name+" age: "+age;
}
}
此时执行程序SeriaTest.java,如下:
public static void main(String[] args)
{
String fileUrl = "./example";
FInterfaceObject obj =(FInterfaceObject)read(fileUrl);
System.out.println(obj);
}
,程序输出:
id: 1 name: null age: 0.
之后,将程序SeriaTest.java修改为读入文件"./example2",程序输出如下:
java.io.InvalidClassException:practice.FInterfaceObject; local class incompatible: stream classdescserialVersionUID = 2044314194551933020, local class serialVersionUID =8436122587265072399
atjava.io.ObjectStreamClass.initNonProxy(Unknown Source)
……
null
异常信息表明,本地类序列化版本与流读入对象的序列化版本不一致,可以通过将serialVersionUID改为2044314194551933020L成功读入文件"./example2",但若再读入"./example",又会因序列化版本不一致而报该异常。
若碰到此种情况,就不能通过仅仅修改代码解决问题了。就需要在业务层面上,规避该问题。
因此,一个用于持久化或者网络传输的类,其序列化版本号最好在一开始就显示的在类中声明,这样,即使后面类发生多次变化,使用的serialVersionUID都相同,就不会出现序列化版本号跟随类变化,导致流拒绝读入不同版本的对象的现象。Eclipse中,对实现了接口Serializable的类,若未显示声明serialVersionUID,会显示编译警告提示。
以下是java序列化的思考点:
1、 静态数据域的序列化(基本类型和Object对象)
2、 读的旧类序列化后能调用新的方法吗?
3、 使用序列化机制clone
4、 readResolve()方法
5、 Externalizable接口,实现自己的保存恢复对象数据的方法
6、 修改默认的序列化方法
7、 transient关键字
- java序列化的版本管理
- java 序列化版本的作用
- Java序列化版本ID的知识点
- 序列化之版本管理、克隆
- java serialVersionUID 版本序列化
- java对象版本序列化
- java序列化类的多版本问题
- [疯狂Java]I/O:I/O流的最高境界——对象流(序列化:手动序列化、自动序列化、引用序列化、版本)
- 了解Boost序列化的版本控制
- java 对象序列化和对象反序列化操作时的版本兼容性问题
- Java软件低级错误(八 ):序列化类的多版本问题
- java的序列化
- Java的序列化
- java的序列化
- java的序列化
- Java的序列化
- java的序列化
- java的序列化
- l2_multi.py
- 【JSP】jsp中标签id和name的区别(转)
- greenplum_externaltable_error_http_code_404
- 网上支付原理
- PopupWindow点击外部区域不能消失的解决办法
- java序列化的版本管理
- opengl 学习小结(一)
- myeclipse中tomcat内存大小的设置
- 第一阶段练习
- Linux iptables详解
- Aspect 切点表达式(xml形式,非注解形式的)
- 主流支付平台的业务流程简介
- bellman_ford算法 python实现
- oracle闪回技术恢复误操作数据