- 浏览: 401896 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
di1984HIT:
学习了,学习了~
Jpcap 网络抓包工具 -
Allen_J_Will:
pengtyao 写道Allen_J_Will 写道为何按照楼 ...
使用mod_cluster进行负载均衡初步预研 -
pengtyao:
Allen_J_Will 写道为何按照楼主的步骤,并参考了 h ...
使用mod_cluster进行负载均衡初步预研 -
Allen_J_Will:
为何按照楼主的步骤,并参考了 http://docs.jbos ...
使用mod_cluster进行负载均衡初步预研 -
362980633:
我在项目中写context.xml,项目没有不部署在tomca ...
配置Tomcat的<Context>元素
JAVA系列之对象的序列化与反序列化
1 简介
对象序列化(Serializable)是指将对象转换为字节序列的过程,而反序列化则是根据字节序列恢复对象的过程。
序列化一般用于以下场景:
1.永久性保存对象,保存对象的字节序列到本地文件中;
2.通过序列化对象在网络中传递对象;
3.通过序列化在进程间传递对象。
对象所属的类必须实现Serializable或是Externalizable接口才能被序列化。对实现了Serializable接口的类,其序列化与反序列化采用默认的序列化方式,Externalizable接口是继承了Serializable接口的接口,是对Serializable 的扩展,实现了Externalizable接口的类完全自己控制序列化与反序列化行为。
Java.io.ObjectOutputStream代表对象输出流,其方法writeObject(Object obj)可以实现对象的序列化,将得到的字节序列写到目标输出流中。Java.io.ObjectInputStream代表对象输入流,其 readObject()方法能从源输入流中读取字节序列,将其反序列化为对象,并将其返回。
2 序列化的几种方式
假设定义了一个Customer类,根据Customer实现序列化方式的不同,可能有以下几种序列化方式:
2.1实现Serializable,未定义readObject和writeObject方法
ObjectOutputStream使用JDK默认方式对Customer对象的非transient的实例变量进行序列化;
ObjectInputStream使用JDK默认方式对Customer对象的非transient的实例变量进行反序列化。
2.2 实现Serializable,并定义了readObject和writeObject方法
ObjectOutputStream调用Customer类的writeObject(ObjectOutputStream out)方法对Customer对象的非transient的实例变量进行序列化;
ObjectInputStream调用Customer类的readObject(ObjectInputStream in)方法对Customer对象的非transient的实例变量进行反序列化。
2.3 实现Externalizable,定义readExternal和writeExternal方法
ObjectOutputStream调用Customer类的writeExternal方法对Customer对象的非transient实例变量进行序列化;
ObjectInputStream首先通过Customer类的无参数构造函数实例化一个对象,再用readExternal方法对Customer对象的非transient实例变量进行反序列化。
3 Serializable接口
类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义。
在反序列化过程中,将使用该类的公用或受保护的无参数构造方法初始化不可序列化类的字段。可序列化的子类必须能够访问无参数构造方法。可序列化子类的字段将从该流中恢复。
当遍历一个类视图时,可能会遇到不支持 Serializable 接口的对象。在此情况下,将抛出 NotSerializableException,并将标识不可序列化对象的类。
3.1 准确签名
在序列化和反序列化过程中需要特殊处理的类必须使用下列准确签名来实现特殊方法:
private void writeObject(java.io.ObjectOutputStream out) throws IOException
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;
private void readObjectNoData() throws ObjectStreamException;
writeObject 方法负责写入特定类的对象的状态,以便相应的 readObject 方法可以恢复它。通过调用 out.defaultWriteObject 可以调用保存 Object 的字段的默认机制。该方法本身不需要涉及属于其超类或子类的状态。通过使用 writeObject 方法或使用 DataOutput 支持的用于基本数据类型的方法将各个字段写入 ObjectOutputStream,状态可以被保存。
readObject 方法负责从流中读取并恢复类字段。它可以调用 in.defaultReadObject 来调用默认机制,以恢复对象的非静态和非瞬态字段。defaultReadObject 方法使用流中的信息来分配流中通过当前对象中相应指定字段保存的对象的字段。这用于处理类演化后需要添加新字段的情形。该方法本身不需要涉及属于其超类或子类的状态。通过使用 writeObject 方法或使用 DataOutput 支持的用于基本数据类型的方法将各个字段写入 ObjectOutputStream,状态可以被保存。
在序列化流不列出给定类作为将被反序列化对象的超类的情况下,readObjectNoData 方法负责初始化特定类的对象状态。这在接收方使用的反序列化实例类的版本不同于发送方,并且接收者版本扩展的类不是发送者版本扩展的类时发生。在序列化流已经被篡改时也将发生;因此,不管源流是“敌意的”还是不完整的,readObjectNoData 方法都可以用来正确地初始化反序列化的对象。
将对象写入流时需要指定要使用的替代对象的可序列化类,应使用准确的签名来实现此特殊方法:
ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
此 writeReplace 方法将由序列化调用,前提是如果此方法存在,而且它可以通过被序列化对象的类中定义的一个方法访问。因此,该方法可以拥有私有 (private)、受保护的(protected) 和包私有 (package-private) 访问。子类对此方法的访问遵循 java 访问规则。
在从流中读取类的一个实例时需要指定替代的类应使用的准确签名来实现此特殊方法。
ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
此 readResolve 方法遵循与 writeReplace 相同的调用规则和访问规则。
如果一个类定义了readResolve方法,那么在反序列化的最后将调用readResolve方法,该方法返回的对象为反序列化的最终结果。
3.2 serialVersionUID
序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。如果接收者加载的该对象的类的 serialVersionUID 与对应的发送者的类的版本号不同,则反序列化将会导致 InvalidClassException。可序列化类可以通过声明名为 "serialVersionUID" 的字段(该字段必须是静态 (static)、最终 (final) 的 long 型字段)显式声明其自己的 serialVersionUID:
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值,如“Java(TM) 对象序列化规范”中所述。不过,强烈建议 所有可序列化类都显式声明 serialVersionUID 值,原因是计算默认的 serialVersionUID 对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的 InvalidClassException。因此,为保证 serialVersionUID 值跨不同 java 编译器实现的一致性,序列化类必须声明一个明确的 serialVersionUID 值。还强烈建议使用 private 修饰符显示声明 serialVersionUID(如果可能),原因是这种声明仅应用于直接声明类 -- serialVersionUID 字段作为继承成员没有用处。数组类不能声明一个明确的 serialVersionUID,因此它们总是具有默认的计算值,但是数组类没有匹配 serialVersionUID 值的要求。
4 Externalizable接口
Externalizable是Serailizable的扩展,实现Externalizable接口的类其序列化有以下特点:
序列化时调用类的方法writeExternal,反序列化调用readExternal方法;
在执行反序列化时先调用类的无参数构造函数,这一点与默认的反序列化是不同的,因此对实现Externalizable接口来实现序列化的类而言,必须提供一个public的无参数构造函数,否则在反序列化时将出现异常。
5 总结
如果采用默认的序列化方式,只要让一个类实现Serializable接口,其实例就可以被序列化。通常,专门为继承而设计的类应该尽量不要实现Serializable接口,因为一旦父类实现了Serializable接口,其所有子类也都是可序列化的了。
默认的序列化方式的不足之处:
1.直接对对象的不宜对外公开的敏感数据进行序列化,这是不安全的;
2.不会检查对象的成员变量是否符合正确的约束条件,有可能被传改数据而导致运行异常;
3.需要对对象图做递归遍历,如果对象图很复杂,会消耗很多资源,设置引起Java虚拟机的堆栈溢出;
4.使类的接口被类的内部实现约束,制约类的升级与维护。
通过实现Serializable接口的private类型的writeObject()和readObject(),或是实现 Externalizable接口,并实现writeExternal()与readExternal()方法,并提供public类型的无参数构造函数两种方式来控制序列化过程可以有效规避默认序列化方式的不足之处。
原文:http://zhupan.iteye.com/blog/26447
1 简介
对象序列化(Serializable)是指将对象转换为字节序列的过程,而反序列化则是根据字节序列恢复对象的过程。
序列化一般用于以下场景:
1.永久性保存对象,保存对象的字节序列到本地文件中;
2.通过序列化对象在网络中传递对象;
3.通过序列化在进程间传递对象。
对象所属的类必须实现Serializable或是Externalizable接口才能被序列化。对实现了Serializable接口的类,其序列化与反序列化采用默认的序列化方式,Externalizable接口是继承了Serializable接口的接口,是对Serializable 的扩展,实现了Externalizable接口的类完全自己控制序列化与反序列化行为。
Java.io.ObjectOutputStream代表对象输出流,其方法writeObject(Object obj)可以实现对象的序列化,将得到的字节序列写到目标输出流中。Java.io.ObjectInputStream代表对象输入流,其 readObject()方法能从源输入流中读取字节序列,将其反序列化为对象,并将其返回。
2 序列化的几种方式
假设定义了一个Customer类,根据Customer实现序列化方式的不同,可能有以下几种序列化方式:
2.1实现Serializable,未定义readObject和writeObject方法
ObjectOutputStream使用JDK默认方式对Customer对象的非transient的实例变量进行序列化;
ObjectInputStream使用JDK默认方式对Customer对象的非transient的实例变量进行反序列化。
2.2 实现Serializable,并定义了readObject和writeObject方法
ObjectOutputStream调用Customer类的writeObject(ObjectOutputStream out)方法对Customer对象的非transient的实例变量进行序列化;
ObjectInputStream调用Customer类的readObject(ObjectInputStream in)方法对Customer对象的非transient的实例变量进行反序列化。
2.3 实现Externalizable,定义readExternal和writeExternal方法
ObjectOutputStream调用Customer类的writeExternal方法对Customer对象的非transient实例变量进行序列化;
ObjectInputStream首先通过Customer类的无参数构造函数实例化一个对象,再用readExternal方法对Customer对象的非transient实例变量进行反序列化。
3 Serializable接口
类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义。
在反序列化过程中,将使用该类的公用或受保护的无参数构造方法初始化不可序列化类的字段。可序列化的子类必须能够访问无参数构造方法。可序列化子类的字段将从该流中恢复。
当遍历一个类视图时,可能会遇到不支持 Serializable 接口的对象。在此情况下,将抛出 NotSerializableException,并将标识不可序列化对象的类。
3.1 准确签名
在序列化和反序列化过程中需要特殊处理的类必须使用下列准确签名来实现特殊方法:
private void writeObject(java.io.ObjectOutputStream out) throws IOException
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;
private void readObjectNoData() throws ObjectStreamException;
writeObject 方法负责写入特定类的对象的状态,以便相应的 readObject 方法可以恢复它。通过调用 out.defaultWriteObject 可以调用保存 Object 的字段的默认机制。该方法本身不需要涉及属于其超类或子类的状态。通过使用 writeObject 方法或使用 DataOutput 支持的用于基本数据类型的方法将各个字段写入 ObjectOutputStream,状态可以被保存。
readObject 方法负责从流中读取并恢复类字段。它可以调用 in.defaultReadObject 来调用默认机制,以恢复对象的非静态和非瞬态字段。defaultReadObject 方法使用流中的信息来分配流中通过当前对象中相应指定字段保存的对象的字段。这用于处理类演化后需要添加新字段的情形。该方法本身不需要涉及属于其超类或子类的状态。通过使用 writeObject 方法或使用 DataOutput 支持的用于基本数据类型的方法将各个字段写入 ObjectOutputStream,状态可以被保存。
在序列化流不列出给定类作为将被反序列化对象的超类的情况下,readObjectNoData 方法负责初始化特定类的对象状态。这在接收方使用的反序列化实例类的版本不同于发送方,并且接收者版本扩展的类不是发送者版本扩展的类时发生。在序列化流已经被篡改时也将发生;因此,不管源流是“敌意的”还是不完整的,readObjectNoData 方法都可以用来正确地初始化反序列化的对象。
将对象写入流时需要指定要使用的替代对象的可序列化类,应使用准确的签名来实现此特殊方法:
ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
此 writeReplace 方法将由序列化调用,前提是如果此方法存在,而且它可以通过被序列化对象的类中定义的一个方法访问。因此,该方法可以拥有私有 (private)、受保护的(protected) 和包私有 (package-private) 访问。子类对此方法的访问遵循 java 访问规则。
在从流中读取类的一个实例时需要指定替代的类应使用的准确签名来实现此特殊方法。
ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
此 readResolve 方法遵循与 writeReplace 相同的调用规则和访问规则。
如果一个类定义了readResolve方法,那么在反序列化的最后将调用readResolve方法,该方法返回的对象为反序列化的最终结果。
3.2 serialVersionUID
序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。如果接收者加载的该对象的类的 serialVersionUID 与对应的发送者的类的版本号不同,则反序列化将会导致 InvalidClassException。可序列化类可以通过声明名为 "serialVersionUID" 的字段(该字段必须是静态 (static)、最终 (final) 的 long 型字段)显式声明其自己的 serialVersionUID:
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值,如“Java(TM) 对象序列化规范”中所述。不过,强烈建议 所有可序列化类都显式声明 serialVersionUID 值,原因是计算默认的 serialVersionUID 对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的 InvalidClassException。因此,为保证 serialVersionUID 值跨不同 java 编译器实现的一致性,序列化类必须声明一个明确的 serialVersionUID 值。还强烈建议使用 private 修饰符显示声明 serialVersionUID(如果可能),原因是这种声明仅应用于直接声明类 -- serialVersionUID 字段作为继承成员没有用处。数组类不能声明一个明确的 serialVersionUID,因此它们总是具有默认的计算值,但是数组类没有匹配 serialVersionUID 值的要求。
4 Externalizable接口
Externalizable是Serailizable的扩展,实现Externalizable接口的类其序列化有以下特点:
序列化时调用类的方法writeExternal,反序列化调用readExternal方法;
在执行反序列化时先调用类的无参数构造函数,这一点与默认的反序列化是不同的,因此对实现Externalizable接口来实现序列化的类而言,必须提供一个public的无参数构造函数,否则在反序列化时将出现异常。
5 总结
如果采用默认的序列化方式,只要让一个类实现Serializable接口,其实例就可以被序列化。通常,专门为继承而设计的类应该尽量不要实现Serializable接口,因为一旦父类实现了Serializable接口,其所有子类也都是可序列化的了。
默认的序列化方式的不足之处:
1.直接对对象的不宜对外公开的敏感数据进行序列化,这是不安全的;
2.不会检查对象的成员变量是否符合正确的约束条件,有可能被传改数据而导致运行异常;
3.需要对对象图做递归遍历,如果对象图很复杂,会消耗很多资源,设置引起Java虚拟机的堆栈溢出;
4.使类的接口被类的内部实现约束,制约类的升级与维护。
通过实现Serializable接口的private类型的writeObject()和readObject(),或是实现 Externalizable接口,并实现writeExternal()与readExternal()方法,并提供public类型的无参数构造函数两种方式来控制序列化过程可以有效规避默认序列化方式的不足之处。
原文:http://zhupan.iteye.com/blog/26447
发表评论
-
通过JUnit理解反射与注解的使用方式与场景
2014-04-07 22:20 1619通过JUnit深入理解反射与注 解的使用方式与场景 引用 ... -
SiteMesh----Web界面布局、装饰框架
2013-06-02 22:48 1797一、SiteMesh项目简介 ... -
DWR--远程服务器端Ajax开源框架
2013-03-17 22:04 1381简介 DWR(Direct Web Remoting)是一个用 ... -
Jpcap 网络抓包工具
2012-07-22 15:17 145751.jpcap说明与安装 JAVA语言虽然在TCP/U ... -
初识敏捷开发
2011-12-27 23:50 1038敏捷软件开发宣言 个体 ... -
XStream序列化与反序列化对象
2011-12-25 19:50 6495XStream是一个将java对象序列化为xml以及从xml反 ... -
持续集成(Continous Integration)
2011-12-14 23:46 1302对持续集成的理解: 1、持续集成是敏捷开发的一种重要实践; 2 ... -
ConcurrentHashMap原理分析
2011-06-09 15:05 4665集合是编程中最常用的数据结构。而谈到并发,几乎总是离不开集合这 ... -
开发知识整理----数组和集合框架(2011-06)
2011-06-07 17:36 1675一、数组 Java数组 ... -
开发知识整理----多线程(2011-05)
2011-05-29 23:21 1356一.多线程 1.进程与线 ... -
动态数组:java.lang.System下的arraycopy和java.util.Arrays.copyOf方法
2011-05-24 00:24 16135java.lang.System下的arraycopy和jav ... -
Java多线程设计模式:wait/notify机制
2011-05-20 00:32 1196引用内容摘要:如果条件不满足,则等待。当条件满足时,等待该条件 ... -
开发知识整理(2011-04)
2011-04-20 10:54 11511.对象的哪些属性与方法应该公开,哪些应该隐藏? 封装两大原则 ... -
近期开发能力加强与整理计划
2011-04-18 23:15 1190在这埋下的种子没有发芽... 也许真不适合... 不得已要换块 ... -
Junit设计模式学习
2011-04-12 23:05 1185Junit设计模式学习 -
instanceof VS isAssignableFrom
2011-04-06 00:49 1141public static void main(Str ... -
c:forEach标签的使用
2011-03-19 17:02 1147c:forEach标签的使用 在JSP的开发中,迭代是经常要 ... -
a4j:jsFunction & a4j:actionparam
2011-03-17 21:28 3747这次JSF的项目中遇到一种特殊情况,在一个CommandLin ... -
JSF f:loadBundle标签
2011-03-16 11:04 1565JSF f:loadBundle标签是JSF提供的一个支持JS ... -
cookie与session专题
2011-03-10 19:55 1001一、cookie机制和session机 ...
相关推荐
Java对象的序列化和反序列化是Java编程中一项重要的技术,主要用于将对象的状态转换为字节流,以便存储或在网络上传输。这一过程对于理解Java的IO操作、持久化数据以及实现分布式通信等场景非常关键。 首先,我们来...
Xson是一个Java对象序列化和反序列化程序。支持Java对象到字节数组的序列化,和从字节数组到Java对象的反序列化。 Maven: <groupId>com.github.xsonorg</groupId> <artifactId>xson-core <version>1.0.1 ...
综上,Java对象序列化和反序列化是Java开发中的基础技能,它们在数据持久化、网络通信等方面发挥着关键作用。了解并掌握这些知识,能够帮助开发者更好地设计和实现各种功能。在实际应用中,需要注意安全性和版本兼容...
java 序列化和反序列化的方法 Java 序列化和反序列化是 Java 语言中的一种机制,用于将对象转换为字节流,以便在网络上传输或存储。序列化是将对象转换为字节流的过程,而反序列化是将字节流转换回对象的过程。 在...
Java对象的序列化和反序列化...总的来说,Java对象的序列化与反序列化是Java平台中一种强大的工具,它能够帮助开发者在多种场景下有效地处理对象数据。理解并掌握这项技术,对于提升Java应用程序的性能和功能至关重要。
本篇文章将深入探讨C#和Java中的序列化与反序列化机制。 首先,我们要了解什么是序列化。序列化是指将对象的状态转化为可存储或可传输的数据格式的过程。这个过程通常将内存中的对象转换成字节流,以便保存到磁盘、...
Java反序列化是一种将已序列化的对象状态转换回对象的过程,它是Java平台中持久化数据的一种常见方式。在Java应用程序中,序列化用于保存对象的状态以便稍后恢复,或者在网络间传输对象。然而,这个过程也可能引入...
Java的序列化与反序列化是Java开发中的一项重要技术,它允许我们将对象的状态转换为字节流,以便存储或在网络上传输。`Serializable`接口是Java提供的一个标记接口,用于实现对象的序列化。当一个类实现了这个接口,...
### C#对象序列化与反序列化 #### 1. 对象序列化的介绍 ##### (1).NET支持对象序列化的几种方式 .NET框架提供了多种序列化机制,它们各自有不同的应用场景和特点。 - **二进制序列化**: - **定义**:二进制...
### Java对象序列化标准知识点详解 #### 一、系统架构概览 **1.1 概览** Java 对象序列化是一种将Java对象的状态转换成字节流的过程,以便于在网络上传输或存储到磁盘上。Java序列化标准定义了一套规则来描述如何...
Java对象的序列化与反序列化是Java编程中一项重要的技术,它允许我们将Java对象转换为字节流,便于存储、传输或者在网络间传递。这一过程对于数据持久化、跨进程通信(如RMI,Remote Method Invocation)以及分布式...
下面是一个简单的序列化示例代码,展示了如何将一个`Box`对象序列化并存储到文件中,然后再从文件中读取出来: ```java package com.hotye.dchaoxiong.serializabletest; import java.io.FileInputStream; import ...
总结,Java对象的序列化和反序列化是Java开发中不可或缺的一部分,理解并熟练掌握这些技术可以帮助我们更好地处理数据存储和传输的问题。在实际操作时,应根据具体需求选择合适的方法,并注意相关的安全和性能问题。
Java中的JSON(JavaScript Object Notation)序列化与反序列化是开发过程中常见且重要的操作,主要用于数据交换和存储。JSON是一种轻量级的数据交换格式,它允许我们将Java对象转换为JSON字符串,反之亦然,方便在...
总之,Java对象序列化是Java开发中的一项关键技术,它允许对象的状态在不同环境间传输和恢复。理解并掌握序列化和反序列化的基本原理、方法以及注意事项,对于开发高质量的Java应用程序至关重要。
极好的序列化与发序列化代码。可以处理array集合,数组或者单个对象等的序列化与反序列化。
### Java序列化与反序列化详解 #### 一、Java序列化概述 Java序列化(Serialization)是一项重要的功能,它可以将对象的状态转化为一系列字节,从而实现对象的持久化存储或在网络上传输。序列化机制使得Java对象...
一、Java对象序列化与反序列化 1. **序列化**: 序列化是将Java对象转换为字节流的过程,以便于存储或传输。通过实现`java.io.Serializable`接口,一个Java对象可以获得序列化的能力。序列化不仅可以保存对象的状态...
上述工具类提供了序列化的方法`mySerialize()`,它接受一个对象和一个文件名作为参数,将对象序列化并保存到指定的文件中。 反序列化则是将字节流转换回原来的对象,这个过程可以通过`ObjectInputStream`类的`...