15.8.2 使用对象流实现序列化
15.8.2 使用对象流实现序列化
如果需要将某个对象保存到磁盘上或者通过网络传输,那么这个类应该实现Serializable
接口或者Externalizable
接口之一。关于这两个接口的区别和联系,后面将有更详细的介绍,读者先不去理会Externalizable
接口。
使用Serializable
来实现序列化非常简单,主要让目标类实现Serializable
标记接口即可,无须实现任何方法.
序列化对象步骤
一旦某个类实现了Serializable
接口,该类的对象就是可序列化的,程序可以通过如下两个步骤来序列化该对象。
1. 创建objectOutputStream
创建一个ObjectorOutputStream
,这个输出流是一个处理流,所以必须建立在其他节点流的基础之上。如下代码所示。
1 | // 创建个 Objectoutputstream输出流 |
2. 调用writeObject方法
调用ObjectOutputStream
对象的writeObject
方法输出可序列化对象,如下代码所示。
1 | // 将一个 Person对象输出到输出流中 |
程序 对象序列化
下面程序定义了一个Person
类,这个Person
类就是一个普通的Java
类,只是实现了Serializable
接口,该接口标识该类的对象是可序列化的。
1
2
3
4
5
6
7
8
9
10
11
12
13public class Person implements java.io.Serializable {
private static final long serialVersionUID = 3069227031912694124L;
private String name;
private int age;
// 注意此处没有提供无参数的构造器!
public Person(String name, int age) {
System.out.println("有参数的构造器");
this.name = name;
this.age = age;
}
// 省略name与age的setter和getter方法
}
下面程序使用ObjectOutputStream
将一个Person
对象写入磁盘文件.
1 | import java.io.*; |
上面程序中的1号代码创建了一个ObjectOutputStream
输出流,这个ObjectOutputStream
输出流建立在一个文件输出流的基础之上;
程序中的2号代码使用writeObject()
方法将一个Person
对象写入输出流。
运行上面程序,将会看到生成了一个object.txt
文件,该文件的内容就是Person
对象.
对象反序列化步骤
如果希望从二进制流中恢复Java
对象,则需要使用反序列化。反序列化的步骤如下。
1. 创建ObjectInputStream
这个输入流是一个处理流,所以必须建立在其他节点流的基础之上。如下代码所示:
1 | //创建一个ObjectInputstream输入流 |
2. 调用readObject方法
调用ObjectInputStream
对象的readObject()
方法读取流中的对象,该方法返回一个Object
类型的Java
对象,如果程序知道该Java
对象的类型,则可以将该对象强制类型转换成其真实的类型。如下代码所示:
1 | //从输入流中读取一个Java对象,并将其强制类型转换为 Person类 |
程序 对象反序列化
下面程序示范了从刚刚生成的object.txt
文件中读取Person
对象的步骤。
1 | import java.io.*; |
上面程序中1号代码将一个文件输入流包装成ObjectInputStream
输入流,
2号代码使用readObject()
方法读取了文件中的Java
对象,这就完成了反序列化过程。
运行结果:
1 | 名字为:孙悟空 |
反序列化只能恢复对象的数据
必须指出的是,反序列化读取的仅仅是Java
对象的数据,而不是Java
类,因此采用反序列化恢复Java
对象时,必须提供该Java
对象所属类的class
文件,否则将会引发ClassNotFoundException
异常。
在ObjectInputStream
输入流中的readObject()
方法声明抛出了ClassNotFoundException
异常,也就是说,当反序列化时找不到对应的Java
类时将会引发该异常。
反序列化不会调用构造器
还有一点需要指出:Person
类只有一个有参数的构造器,没有无参数的构造器,而且该构造器内有个普通的打印语句。当反序列化读取Java
对象时,并没有看到程序调用该构造器,这表明反序列化机制无须通过构造器来初始化Java
对象。
反序列化读取对象时要按序列化时的写入的顺序读取
如果使用序列化机制向文件中写入了多个Java
对象,使用反序列化机制恢复对象时必须按实际写入的顺序读取
可序列化类的祖先类要满足的条件
当一个可序列化类有多个父类时(包括直接父类和间接父类),这些父类要么有无参数的构造器,要么也是可序列化的——否则反序列化时将抛出InvalidClassException
异常。
如果父类是不可序列化的,只是带有无参数的构造器,则该父类中定义的成员变量值不会序列化到二进制流中。