第十一周-序列化

一.对象序列化是什么?

对象总是在运行时存在,当程序终止时,对象也就无论如何也不存在了。而序列化即提供了一种机制,通过将“对象持久化”,可以让对象在程序不运行时也能存在。

二.对象序列化的用途是什么?

  1. java远程方法调用(RMI):可以使得远程对象的像在本机上存在一样。当向远程对象发送消息是,需要通过对象序列化来传出参数和返回值。
  2. Java Beans:使用bean时需要在设计阶段对它的状态信息进行配置。这种状态信息会保存下来,并在程序启动时进行恢复。

三.保存和加载序列化对象

为了保存对象数据,需要打开一个ObjectOutputStream对象:

ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("filename"))

为了保存对象,可以直接用ObjectOutputStream 的writeObject方法

Employee harry = new Employee("Harry Hacker",50000,1989,10,1);
out.writeObject(harry);

为了读回对象,首先要获得一个ObjectInputStream对象:

ObjectInputStream in = new ObjectInputStream(new FileInputStream("filename"))

然后,用readObject方法以这些对象写入顺序获取他们:

Employee e1 = (Employee)in.readObject();

注意:保存和加载基本数据类型时,使用基本数据类型对应的方法,如int类型,使用writeInt和readInd。

四.序列化会持久化对象哪些内容?

1.对象序列化不仅保存了对象的“全景图”,而且能追踪对象对所包含的所有引用,并保存那些对象;接着又能对对象内每个引用进行追踪,找到它的引用类,以此类推,形成一个“对象网”。
2.对象序列化是以特殊格式存储对象数据的,如果有兴趣的可以深入了解“对象序列化的文件格式”。这里只做简单介绍:
存储对象时,对象所属类也必须要存储。这个类的描述包括:

  • 类名
  • 序列化的版本唯一ID,他是数据域类型和方法签名的指纹。
  • 描述序列化方法的标志集。
  • 对数据域的描述
    值得注意的点:任何类的完整的类描述符只保存一次,后续描述符将引用它(通过序列化唯一ID)。

五.多对象引用的情况

基于“对象网”特性,如果存在存在多个对象对同一个对象进行引用,如两个经理公用同一个秘书:

Employee harry = new Employee("Harry Hacker",50000,1989,10,1);
Manager carl = new Manager (...);
carl.setSecretary(harry);
Manager tony= new Manager (...);
tony.setSecretary(harry);

这种情况是无法通过保存对象的内存地址来保证秘书是同一个人,因为当对象被重载时,他可能重新占据一块新的地址。
序列化保证每个对象都是用同一个序列号保存。下面是它的算法:

  • 对遇到的每个对象引用都关联一个序列号
  • 对于每个对象,让第一次遇到时,保存其对象数据到输出流中
  • 如果某个对象之前被保存过,那么只写出“与之前保存的序列号为x的对象相同”
    在读回对象时,则是反向操作:
  • 输入流的对象,在第一次遇到其序列号时构建它,并使用流中数据进行初始化,然后记录序列号与对象之间的关联
  • 当遇到“与之前保存的序列号为x的对象相同”标记时,获取与这个序列号相同的引用
    注意:只是同一流中的同一对象会添加“与之前保存的序列号为x的对象相同”标记。不同流时无法保证的。

六.对象序列化的其他方法

上面只介绍了实现Serializable接口的常用序列化方法,序列化包括以下几种方法:

  • 含有writeObject方法的类
  • 实现了Serializable接口的类
  • 实现了Externalizable接口的类

七.屏蔽对象中某些域的方式

有时候我们不希望对象所有的域都被序列化,如用户的密码字段。
这种情况序列化提供了一个transient(瞬时)关键字,通过对对象中的某些不想要序列化的域添加关键字,即可以保证域不被序列化
还有另外一种处理这种情况的方式--使用Externalizable序列化,后续会进行介绍

八.修改默认的序列化机制

通常我们不需要添加额外的方法,Serializable序列化方式就可以自动实现对对象的序列化。但序列化机制也提供了另外一种方式,来屏蔽自动序列化,向默认的读写行为添加验证或其他行为。

private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException;
private void writeObject(ObjectOutputStream in) throws IOException;

通常,在方法的内部我们需要添加defaultWriteObject方法和defaultReadObject方法来保存和加载默认Serializable序列化方式中自动处理的字段(即非transient字段),而对于transient字段,则需要通过writeObject方法和readObject方法来进行保存和加载(是的,你没有看错,transient字段只是无法被默认序列化方式保存和加载)。

九.Externalizable序列化方式

Externalizable序列化方式与Serializable序列化方式的不同点在于:

  1. Externalizable序列化方式不会自动完成序列化,而需要自己定义那些域需要序列化,Externalizable提供了两个方法writeExternalreadExternal,分别显式的保存和加载域。
  2. Externalizable序列化方式会调用构造器。对于Serializable对象,对象完全以它存储的二进制位为基础来构造,而Externalizable对象则会调用所有默认的构造器(包括字段定义时的初始化,如果无法加载出数据,会初始化为null值)

你可能感兴趣的:(第十一周-序列化)