java中的序列号和反序列化

上传人:飞*** 文档编号:39929668 上传时间:2018-05-21 格式:DOCX 页数:6 大小:18.01KB
返回 下载 相关 举报
java中的序列号和反序列化_第1页
第1页 / 共6页
java中的序列号和反序列化_第2页
第2页 / 共6页
java中的序列号和反序列化_第3页
第3页 / 共6页
java中的序列号和反序列化_第4页
第4页 / 共6页
java中的序列号和反序列化_第5页
第5页 / 共6页
点击查看更多>>
资源描述

《java中的序列号和反序列化》由会员分享,可在线阅读,更多相关《java中的序列号和反序列化(6页珍藏版)》请在金锄头文库上搜索。

1、转自 http:/ 简介 对象序列化(Serializable)是指将对象转换为字节序列的过程,而反序列化则是根据字节序列恢复对象的过程。 序列化一般用于以下场景: 1.永久性保存对象,保存对象的字节序列到本地文件中; 2.通过序列化对象在网络中传递对象; 3.通过序列化在进程间传递对象。 对象所属的类必须实现 Serializable 或是 Externalizable 接口才能被序列化。对实现了 Serializable 接口的类,其序列化与反序列化采用默认的序列化方式,Externalizable 接口是继承了 Serializable 接口的接口,是对 Serializable 的扩展

2、,实现了 Externalizable 接口的类完全自己控制序列化与反序列化行为。 Java.io.ObjectOutputStream 代表对象输出流,其方法 writeObject(Object obj)可以实现对象的序列化,将得到的字节序列写到目标输出流中。Java.io.ObjectInputStream 代表对象输入流,其 readObject()方法能从源输入流中读取字节序列,将其反序列化为对象,并将其返回。 2 序列化的几种方式 假设定义了一个 Customer 类,根据 Customer 实现序列化方式的不同,可能有以下几种序列化方式: 2.1 实现 Serializable,

3、未定义 readObject 和 writeObject 方法 ObjectOutputStream 使用 JDK 默认方式对 Customer 对象的非 transient 的实例变量进行序列化; ObjectInputStream 使用 JDK 默认方式对 Customer 对象的非 transient 的实例变量进行反序列化。 2.2 实现 Serializable,并定义了 readObject 和 writeObject 方法 ObjectOutputStream 调用 Customer 类的 writeObject(ObjectOutputStream out)方法对 Custom

4、er 对象的非 transient 的实例变量进行序列化; ObjectInputStream 调用 Customer 类的 readObject(ObjectInputStream in)方法对 Customer 对象的非transient 的实例变量进行反序列化。 2.3 实现 Externalizable,定义 readExternal 和 writeExternal 方法 ObjectOutputStream 调用 Customer 类的 writeExternal 方法对 Customer 对象的非 transient 实例变量进行序列化; ObjectInputStream 首先通

5、过 Customer 类的无参数构造函数实例化一个对象,再用 readExternal 方法对Customer 对象的非 transient 实例变量进行反序列化。 3 Serializable 接口 类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义。 在反序列化过程中,将使用该类的公用或受保护的无参数构造方法初始化不可序列化类的字段。可序列化的子类必须能够访问无参数构造方法。可序列化子类的字段将从该流中恢复。 当遍历一个

6、类视图时,可能会遇到不支持 Serializable 接口的对象。在此情况下,将抛出 NotSerializableException,并将标识不可序列化对象的类。 3.1 准确签名 在序列化和反序列化过程中需要特殊处理的类必须使用下列准确签名来实现特殊方法: private void writeObject(java.io.ObjectOutputStream out) throws IOException private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundExcept

7、ion; private void readObjectNoData() throws ObjectStreamException; writeObject 方法负责写入特定类的对象的状态,以便相应的 readObject 方法可以恢复它。通过调用 out.defaultWriteObject 可以调用保存 Object 的字段的默认机制。该方法本身不需要涉及属于其超类或子类的状态。通过使用 writeObject 方法或使用 DataOutput 支持的用于基本数据类型的方法将各个字段写入 ObjectOutputStream,状态可以被保存。 readObject 方法负责从流中读取并恢复

8、类字段。它可以调用 in.defaultReadObject 来调用默认机制,以恢复对象的非静态和非瞬态字段。defaultReadObject 方法使用流中的信息来分配流中通过当前对象中相应指定字段保存的对象的字段。这用于处理类演化后需要添加新字段的情形。该方法本身不需要涉及属于其超类或子类的状态。通过使用 writeObject 方法或使用 DataOutput 支持的用于基本数据类型的方法将各个字段写入 ObjectOutputStream,状态可以被保存。 在序列化流不列出给定类作为将被反序列化对象的超类的情况下,readObjectNoData 方法负责初始化特定类的对象状态。这在接

9、收方使用的反序列化实例类的版本不同于发送方,并且接收者版本扩展的类不是发送者版本扩展的类时发生。在序列化流已经被篡改时也将发生;因此,不管源流是“敌意的”还是不完整的,readObjectNoData 方法都可以用来正确地初始化反序列化的对象。 将对象写入流时需要指定要使用的替代对象的可序列化类,应使用准确的签名来实现此特殊方法: ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException; 此 writeReplace 方法将由序列化调用,前提是如果此方法存在,而且它可以通过被序列化对象的类中定义的一个方法访问

10、。因此,该方法可以拥有私有 (private)、受保护的(protected) 和包私有 (package-private) 访问。子类对此方法的访问遵循 java 访问规则。 在从流中读取类的一个实例时需要指定替代的类应使用的准确签名来实现此特殊方法。 ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException; 此 readResolve 方法遵循与 writeReplace 相同的调用规则和访问规则。 如果一个类定义了 readResolve 方法,那么在反序列化的最后将调用 readResolve 方法,该

11、方法返回的对象为反序列化的最终结果。 3.2 serialVersionUID 序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。如果接收者加载的该对象的类的 serialVersionUID 与对应的发送者的类的版本号不同,则反序列化将会导致 InvalidClassException。可序列化类可以通过声明名为 “serialVersionUID“ 的字段(该字段必须是静态 (static)、最终 (final) 的 long 型字段)显式声明其自己的 s

12、erialVersionUID: ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L; 如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值,如“Java(TM) 对象序列化规范”中所述。不过,强烈建议 所有可序列化类都显式声明 serialVersionUID 值,原因是计算默认的 serialVersionUID 对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的 Invali

13、dClassException。因此,为保证 serialVersionUID 值跨不同 java 编译器实现的一致性,序列化类必须声明一个明确的 serialVersionUID 值。还强烈建议使用 private 修饰符显示声明 serialVersionUID(如果可能),原因是这种声明仅应用于直接声明类 - serialVersionUID 字段作为继承成员没有用处。数组类不能声明一个明确的 serialVersionUID,因此它们总是具有默认的计算值,但是数组类没有匹配 serialVersionUID 值的要求。 4 Externalizable 接口 Externalizabl

14、e 是 Serailizable 的扩展,实现 Externalizable 接口的类其序列化有以下特点: 序列化时调用类的方法 writeExternal,反序列化调用 readExternal 方法; 在执行反序列化时先调用类的无参数构造函数,这一点与默认的反序列化是不同的,因此对实现Externalizable 接口来实现序列化的类而言,必须提供一个 public 的无参数构造函数,否则在反序列化时将出现异常。 5 总结 如果采用默认的序列化方式,只要让一个类实现 Serializable 接口,其实例就可以被序列化。通常,专门为继承而设计的类应该尽量不要实现 Serializable

15、接口,因为一旦父类实现了 Serializable 接口,其所有子类也都是可序列化的了。 默认的序列化方式的不足之处: 1.直接对对象的不宜对外公开的敏感数据进行序列化,这是不安全的; 2.不会检查对象的成员变量是否符合正确的约束条件,有可能被传改数据而导致运行异常; 3.需要对对象图做递归遍历,如果对象图很复杂,会消耗很多资源,设置引起 Java 虚拟机的堆栈溢出; 4.使类的接口被类的内部实现约束,制约类的升级与维护。 通过实现 Serializable 接口的 private 类型的 writeObject()和 readObject(),或是实现 Externalizable 接口,并实现 writeExternal()与 readExternal()方法,并提供 public 类型的无参数构造函数两种方式来控制序列化过程可以有效规避默认序列化方式的不足之处。

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > 其它办公文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号