序列化是将对象变为连续的字节流,用于对象的持久化,网络传输等场合
一个类希望能被序列化必须实现 Serializable 接口,Serializable 本身并没有声明任何
方法,只是起标记作用。可序列化类的子类自然也是可序列化的。因而实现序列化是非常方
便的,只要在类的声明时添加 implenment Serializable 就可以了,java 虚拟机会帮你处
理剩下的工作。序列化是递归的,一个类想要序列化则它的所有数据成员都必须是可以序列
化的,否则在序列化时会抛出 NotSerializableException 异常。jsdk 中基本数据类型的
封装类(Integer, Float etc),Component 都是可序列化的,如果容器中的对象都是可
序列化的,则容器时可序列化的。java.lang.refect 包中的类不能序列化,Socket,
URLConnection 不能序列化。
对于只实现了 Serializable 接口的类,可以想象 java 是如何将它们序列化的:首先要利
用反射机制得到所有需要序列化的数据成员,包括 private 成员,得到 private 成员的过
程是非常规的,必定要经过严格的权限和安全检查。所以用 java 自己的序列化方式开销是
非常大的,这也是为什么会有这篇文章的原因,这里要讨论 java 提供的可以由我们自己控
制的序列化对象的方式。
覆写
private void writeObject(ObjectOutputStream out)
private void readObject(ObjectInputStream in)
这两个方法会在对象序列化和反序列化时被调用,通过覆写这两个方法我们可以完全控制整
个序列化的过程。我们注意到这两个方法都是 private ,这意味我们无法显示的调用这两
个方法,而 java 虚拟机在调用这两个方法时也必然要经过严格的权限和安全检查。与传统
的序列化方式(只实现 Serializable 接口)相比,这种方法减少了利用反射的次数以及获
取 private 成员所需要的额外开销,因为在这两个方法中所有的数据成员都是可以自由使
用的
实现 Externalizable 接口
该接口中定义了两个方法
public void readExternal(ObjectInput in) throws IOException
public void writeExternal(ObjectOutput out)
throws IOException, ClassNotFoundException
这两个方法会在对象序列化和反序列化时被调用。很明显这两个方法都是 public 的,所以
我们可以显示的将一个对象序列化到一个输出流,而 java 虚拟机在调用这两个方法时也不
会有任何的限制。
ANY-ACCESS_MODIFIER Object writeReplace() throws ObjectStreamException;
ANY-ACCESS_MODIFIER Object readResolve() throws ObjectStreamException;
这两个方法在序列化和反序列化时被调用,可以替换将要写入或读出的对象,在实现Singleton模式
时可能会用到
这三种方法实现序列化效率是显而易见的:传统方式最慢,实现 Externalizable 接口方式
最快。但自己控制序列化过程有个明显的缺点就是当类的数据成员改变时,序列化过程也同
时需要修改,相反这正好是传统方式的优点:任何改动都不会影响对象的正确序列化,虚拟
机会帮你完成一切工作,虽然不算出色。
当我们考虑性能问题时,序列化总应该是我们首先要注意的方面,尤其是那些只实现了
Serializable 接口的类,它们往往就是性能的瓶颈所在,特别是一些对象需要反复的被序
列化和反序列化,实现 Externalizable 接口会给你不小的惊喜。而对于实现
Externalizable 接口后需要保持数据成员和序列化方法一致的问题实际算不上问题,因为
当我们考虑性能问题时应该已经到了编码的最后阶段,这时整体框架和数据结构都已经非常
稳定了,数据成员被修改的可能已经非常低了,即使被修改了,能大幅提高性能,多写两行代
码也不是令人沮丧的事情。
以上只是单纯的讨论序列化的过程,实际上序列化总是和 I/O 操作同时发生,因为序列化
就是为了传输或是存储,所以对 I/O 的优化方法在这里也是同样适用的。
使用ObjectOutputStream.writeObject()时,在流的内部会有一个引用缓存,所有已经写入流的
对象如果再次被写入则直接使用以前引用而不重新传输新的对象,这样可以提到流的效率,但同样带来
问题,一个对象写入流后,被修改,再次写入流,再另一端ObjectInputStream得到的是
两个相同的对象,这一点一定要注意
posted on 2005-09-09 14:07
JBahamut 阅读(634)
评论(3) 编辑 收藏