什么是序列化
java中的序列化(serialization)机制能够将一个实例对象的状态信息写入到一个字节流中,使其可以通过socket进行传输、或者持久化存储到数据库或文件系统中;然后在需要的时候,可以根据字节流中的信息来重构一个相同的对象。序列化机制在java中有着广泛的应用,EJB、RMI等技术都是以此为基础的。
正确使用序列化机制
一般而言,要使得一个类可以序列化,只需简单实现
java.io.Serializable接口即可。该接口是一个标记式接口,它本身不包含任何内容,实现了该接口则表示这个类准备支持序列化的功能。如下例定义了类Person,并声明其可以序列化。
public class Person implements java.io.Serializable {}
序列化机制是通过
java.io.ObjectOutputStream类和
java.io.ObjectInputStream类来实现的。在序列化(serialize)一个对象的时候,会先实例化一个ObjectOutputStream对象,然后调用其writeObject()方法;在反序列化(deserialize)的时候,则会实例化一个ObjectInputStream对象,然后调用其readObject()方法。下例说明了这一过程。
public void serializeObject(){
String fileName = "ser.out";
FileOutputStream fos = new FileOutputStream(fileName);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(new Person());
oos.flush();
}
public void deserializeObject(){
String fileName = "ser.out";
FileInputStream fos = new FileInputStream(fileName);
ObjectInputStream oos = new ObjectInputStream(fos);
Person p = oos.readObject();
}
上例中我们对一个Person对象定义了序列化和反序列化的操作。但如果Person类是不能序列化的话,即对不能序列化的类进行序列化操作,则会抛出
java.io.NotSerializableException异常。
JVM中有一个预定义的序列化实现机制,即默认调用
ObjectOutputStream.defaultWriteObject() 和
ObjectInputStream.defaultReadObject() 来执行序列化操作。如果想自定义序列化的实现,则必须在声明了可序列化的类中实现
writeObject()和
readObject()方法。
几种使用情况
一般在序列化一个类A的时候,有以下三种情况:
[list=3]
类A没有父类,自己实现了Serializable接口
类A有父类B,且父类实现了Serializable接口
类A有父类B,但父类没有实现Serializable接口
[/list]
对于第一种情况,直接实现Serializable接口即可。
对于第二种情况,因为父类B已经实现了Serializable接口,故类A无需实现此接口;如果父类实现了writeObject()和readObject(),则使用此方法,否则直接使用默认的机制。
对于第三种情况,则必须在类A中显示实现writeObject()和readObject()方法来处理父类B的状态信息;还有一点要特别注意,在父类B中一定要有一个无参的构造函数,这是因为在反序列化的过程中并不会使用声明为可序列化的类A的任何构造函数,而是会调用其没有申明为可序列化的父类B的无参构造函数。
序列化机制的一些问题
[list]
性能问题
为了序列化类A一个实例对象,所需保存的全部信息如下:
1. 与此实例对象相关的全部类的元数据(metadata)信息;因为继承关系,类A的实例对象也是其任一父类的对象。因而,需要将整个继承链上的每一个类的元数据信息,按照从父到子的顺序依次保存起来。
2. 类A的描述信息。此描述信息中可能包含有如下这些信息:类的版本ID(version ID)、表示是否自定义了序列化实现机制的标志、可序列化的属性的数目、每个属性的名字和值、及其可序列化的父类的描述信息。
3. 将实例对象作为其每一个超类的实例对象,并将这些数据信息都保存起来。
在RMI等远程调用的应用中,每调用一个方法,都需要传递如此多的信息量;久而久之,会对系统的性能照成很大的影响。
版本信息
当用readObject()方法读取一个序列化对象的byte流信息时,会从中得到所有相关类的描述信息以及示例对象的状态数据;然后将此描述信息与其本地要构造的类的描述信息进行比较,如果相同则会创建一个新的实例并恢复其状态,否则会抛出异常。这就是序列化对象的版本检测。JVM中默认的描述信息是使用一个长整型的哈希码(hashcode)值来表示,这个值与类的各个方面的信息有关,如类名、类修饰符、所实现的接口名、方法和构造函数的信息、属性的信息等。因而,一个类作一些微小的变动都有可能导致不同的哈希码值。例如开始对一个实例对象进行了序列化,接着对类增加了一个方法,或者更改了某个属性的名称,当再想根据序列化信息来重构以前那个对象的时候,此时两个类的版本信息已经不匹配,不可能再恢复此对象的状态了。要解决这个问题,可能在类中显示定义一个值,如下所示:
private static final long serialVersionUID = ALongValue;
这样,序列化机制会使用这个值来作为类的版本标识符,从而可以解决不兼容的问题。但是它却引入了一个新的问题,即使一个类作了实质性的改变,如增加或删除了一些可序列化的属性,在这种机制下仍然会认为这两个类是相等的。
[/list]
一种更好的选择
作为实现Serializable接口的一种替代方案,实现
java.io.Externalizable接口同样可以标识一个类为可序列化。
Externalizable接口中定义了以下两个方法:
public void readExternal(ObjectInput in);
public void writeExternal(ObjectOutput out);
这两个方法的功能与 readObject()和writeObject()方法相同,任何实现了Externalizable接口的类都需要这实现两个函数来定义其序列化机制。
使用Externalizable比使用Serializable有着性能上的提高。前者序列化一个对象,所需保存的信息比后者要小,对于后者所需保存的第3个方面的信息,前者不需要访问每一个父类并使其保存相关的状态信息,而只需简单地调用类中实现的writeExternal()方法即可。
分享到:
相关推荐
Java反序列化漏洞学习实践中的代码 Java反序列化漏洞学习实践一:从Serializbale接口开始,...Java反序列化漏洞学习实践二:Java的反射机制(Java Reflection) Java反序列化漏洞学习实践三:理解java的动态代理机制
主要介绍了通过实例了解java序列化机制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。下面小编和大家来一起学习一下吧
序列化和反序列化 继承、封装、多态的实现原理 容器 Java集合类总结 Java集合详解1:一文读懂ArrayList,Vector与Stack使用方法和实现原理 Java集合详解2:Queue和LinkedList Java集合详解3:Iterator,fail-fast机制...
JAVA异常处理机制 一、什么异常(Exception) 1.生活中异常:不正常事件(意外) 2.程序异常:异常是指在程序的运行过程中所发生的不 正常的事件(例外,错误),它会中断正在运行的程序。 3.什么是异常处理:java编程语言使用...
学习Java的IO编程,包括文件读写、网络编程和序列化等。 阶段三:Web开发与框架 学习JavaWeb开发的基础知识,包括Servlet、JSP和JDBC等,了解MVC模式。 学习常用的JavaWeb框架,如Spring和Spring MVC,了解依赖注入...
Java 序列化详解 泛型&通配符详解 Java 反射机制详解 Java 代理模式详解 BigDecimal 详解 Java 魔法类 Unsafe 详解 Java SPI 机制详解 Java 语法糖详解 集合 知识点/面试题总结 : Java 集合常见知识点&面试题总结...
Java 序列化详解 泛型&通配符详解 Java 反射机制详解 Java 代理模式详解 BigDecimal 详解 Java 魔法类 Unsafe 详解 Java SPI 机制详解 Java 语法糖详解 集合 知识点/面试题总结: Java 集合常见知识点&面试题总结...
Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...
Student.java 定义一个用来序列化的类 ThreadIn.java 接收数据用的线程类 ThreadOut.java 发送数据用的线程类 TypeFile.java 显示文件内容的类 useScanner.java 用Scanner接收用户的输入 第8章 示例描述:本章...
序列化和反序列化 继承封装多态的实现原理 集合类 Java集合类总结 Java集合详解:一文读懂ArrayList,Vector与Stack使用方法和实现原理 Java集合详解:Queue和LinkedList Java集合详解:迭代器,快速失败机制与比较器...
序列化 nIo 匿名类 包装类 优先级 引用 语言工具类库 容器类 集合 链表 map 工具类 系统类 日期类 数字类 字符串+正则 流 字符流 字节流 语言特性 继承 封装 多态 JVM 多线程与并发 GC...
Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...
Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...
JAVA对象的序列化和反序列化 161 为什么需要序列化和反序列化 161 对象的序列化主要有两种用途 161 序列化涉及的类和接口 162 序列化/反序列化的步骤和实例 162 综合的序列化和反序列化练习 163 JAVA.IO包相关流对象...
主要讲解了System类、Object类、Arrays类、Cloneable接口、IO系统输入输出类及装饰类、IO系统文本读写工具类、IO系统二进制读写工具类、对象序列化工具类、File类及文件搜索工具类、java异常机制及自定义异常类、...
理解通信协议传输过程中的序列化和反序列化机制 基于框架的RPC通信技术 WebService/ApacheCXF RMI/Spring RMI Hession 传统RPC技术在大型分布式架构下面临的问题 分布式架构下的RPC解决方案 Zookeeper ...
Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...
Android 序列化机制在 Android 系统中关于序列化的方法一般有两种,分别是实现 Serializable 接口和 Parcelable 接口Serializable 是来自 Java 中的序列化接口Parcelable 是 Android 自带的序列化接口上述的两种序列...
Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...