§ 1.2 序列化与对象流
内容提要
一般情况下, 在程序中创建的对象会随着程序终止而消失,
但有时希望将某些对象保存起来以备后用, 利用序列化可
以实现对象的, 持久性, 。 可以借助对象流来实现对象序
列化 。 本节的主要内容如下,
? 序列化的概念
? 对象流
? 序列化的控制
§ 1.2 序列化与对象流
任务
HNS软件学院开发部在对图书馆管理系统进行系统分析和概
要设计后, 进入到系统实现阶段 。 在该阶段中, 需要将系
统中对象抽象成类, 并进行代码实现 。 现在有一用户类,
该类的实例保存了图书馆用户的基本信息, 这些信息不应
该随着对象的消亡而消失, 因此, 要求您完成以下的任务,
1,构造用户类, 并要求该类的实例是可序列化的 。 这样,
即使对象消亡了, 用户的信息还能够保存到文件中, 并在
需要时恢复 。
1.2.1 序列化
对象序列化 (serialize)是把对象转换成一个字节序列
的过程, 反之, 将字节序列并完全恢复为原来的对
象的过程, 称为对象的反序列化 (deserialize)。
在 Java程序中, 一般情况下, 在程序中创建的对象
会随着程序终止而消失, 但有时希望将某些对象保
存起来以备后用, 这时就需要用到序列化 。 利用序列化可以实现对象的, 持久性, (persistence)。, 持
久性, 意味着一个对象的生命周期并不取决于程序
是否正在执行, 对象可以生存于程序的调用之间 。
通过将一个序列化对象写入磁盘, 然后在重新调用
程序时恢复该对象, 就能够实现持久性的效果 。
1.2.1 序列化
Java有一套自己的对象序列化机制来保证序列化的
正确执行 。 一个类只要实现了 Serializable接口, 它
的 对 象 就 可 以 被 序 列 化 工 具 存 储 和 恢 复 。
Serializable接口没有定义任何方法, 它只是用来表
示一个类的实例 ──对象可以被序列化 。 要序列化
一个对象, 首先要创建某些 OutputStream对象, 然
后以该对象为参数构造一个 ObjectOutputStream对
象 。 这时, 只需要调用 writeObject()方法即可将对
象序列化, 并将其发送给 OutputStream;要反向进
行该过程 (反序列化 ),需要将一个 InputStream封装
在 ObjectInputStream内, 然后调用 readObject()方法 。
1.2.2 对象流
java.io包有两个序列化对象的类 。 ObjectOutputStream负责将对象写入字节流,
ObjectInputStream从字节流重构对象 。
要存储对象数据, 首先需要打开一个对象输出流类 (ObjectOutputStream)对象, 类
似代码如下,
ObjectOutputStream objectOutput
= new ObjectOutputStream(new FileOutputStream("output.dat"));
要保存对象, 只需要使用 ObjectOutputStream 类的 writeObject() 方法即可 。
writeObject()方法是 ObjectOutputStream类的最重要的方法, 用于对象序列化 。
类似代码如下,
ClassA a = new ClassA();
objectOutput,writeObject(a);
要读回该对象, 首先要获得一个对象输入流类 (ObjectInputStream)对象, 类似代码
如下,
ObjectInputStream objectInput = new ObjectInputStream(new FileInputStream("output.dat"));
然后, 按照写对象同样的顺序, 用 readObject()方法读对象 。 每次调用 readObject()
方法都返回流中下一个对象 。 类似代码如下,
ClassA a = (ClassA)objectInput,readObject();
1.2.2 对象流
示例 1.2.1 用代码实现一个工具类 DateUtility,它可以将一个
Date类的实例保存到文件中, 稍后再从文件中将该实例恢复 。
因此, 该工具类有两个静态的方法分别实现这两个功能,
writeDateToFile方法序列化一个 Date对象并写到文件中;
readDateFromFile方法将先前写入到文件中的 Date对象反序
列化 。
1.2.3 序列化的控制
1,transient关键字
对一个实现了 Serializable接口的对象来说, 所有序列化操作
都会自动的进行 。 但是, 可以使用 transient关键字对序列
化过程进行控制, 将对象中不打算序列化的数据声明成
transient类型后, 这些数据就不会同对象的其余部分一起
被序列化 。
1.2.3 序列化的控制
示例 1.2.2 创建一个 Login对象保存某个特定的登陆会话记录 。
登陆的合法性通过校验后, 希望把数据保存下来, 稍后还
能恢复该数据 。 考虑到安全性的问题, 保存的数据不包括
密码 。 编码实现上述功能 。
1.2.3 序列化的控制
2,Externalizable接口
另一种控制序列化过程的方法是让类实现 Externalizable接口, 而不是
Serializable接口 。 对一个 Serializable对象而言, 所有序列化操作
都会自动进行 (除了用 transient关键字声明不序列化的部分 );对一
个 Externalizable对象而言, 没有任何东西可以自动序列化 。
Externalizable接口提供了两个重要的抽象方法,writeExternal()
和 readExternal()。 一个类如果实现了 Externalizable接口, 就必须
实现这两个抽象方法 。 程序员使用 writeExternal()方法将对象中需
要存储的数据写入, 使用 readExternal()方法恢复对象中的数据 。
Serializable对象与 Externalizable对象另外一个显著的区别是, 它
们恢复对象的机制完全不一样 。 对于 Serializable对象, 恢复对象时
完全以它存储的二进制数据为基础来构造, 没有调用对象的构造函数,
整个对象都是通过从 InputStream中取得数据恢复而来的, 即对象是
被整体恢复的;对于 Externalizable对象, 恢复对象时, 对象通过构
造函数被构造, 所有缺省的构造函数都会被调用 (包括在字段定义时
的初始化 ),然后调用 readExternal()恢复该对象的数据信息, 即对
象是被分步恢复的 。
1.2.3 序列化的控制
示例 1.2.3 修改 示例 1.2.2中的 Login对象, 要求手工实现对
象的序列化 。
任务解决
通过对序列化相关知识的学习, 使我们学会了如何序列化对象, 同时也
初步具备了解决任务的能力 。
分析,
1,用户类包含五个属性:用户类别, ID号, 姓名, 基本信息和密码 。
这些属性应该定义成私有 (private)的, 并通过公有方法 getXXX()和
setXXX()来获得 /设置这些属性
2,用户对象要求能被序列化, 因此, 用户类必须实现 Serializable
接口 。
3,基于安全性的考虑, 用户的密码在序列化的过程中应该被加密 。
encrypt()方法用来加密, decrypt()方法用来解密 。 需要注意的是,
加密过程只不过是在写数据之前颠倒值的顺序, 在将数据读入后再将
值的顺序颠倒回来 。 很显然, 这并不提供任何真正的加密, 在实际应
用中, 用户应该加上符合自己要求的加密代码 。
小结
本节主要学习了以下内容,
一, 序列化
对象序列化是把对象转换成一个字节序列的过程, 反之, 将字节序列并完全恢
复为原来的对象的过程, 称为对象的反序列化 。 利用序列化可以实现对象的
,持久性, 。
二, 对象流
java.io包有两个序列化对象的类 。 ObjectOutputStream负责将对象写入字节流,
ObjectInputStream 从字节流重构对象 。 ObjectInputStream 类和
ObjectOutputStream类分别实现了 ObjectInput接口和 ObjectOutput接口, 因
此, 对象流不仅能读 /写对象, 还能读 /写 Java中的原始类型数据 。
三, 序列化的控制
一个类只有实现了 Serializable接口或者 Externalizable接口, 它的对象才可
以被序列化 。 对一个 Serializable对象而言, 所有序列化操作都会自动进行,
除了用 transient关键字声明不序列化的部分;对一个 Externalizable对象而
言, 没有任何东西可以自动序列化, 程序员必须自己决定对象的哪些部分需
要序列化 。