Java的Externalizable接口
Published:
05 Mar 2014
Category:
Java
在理解Externalizable接口之前,你需要先理解什么是序列化。有关序列化可以读下 这篇文章多了解一些。
Java提供了序列化的机制来把Java对象里持久化成一个有序的字节序列,这里面包括对象的数据及其类型,还有对象本身的类型信息。
Externalizable:
就如名字所说的,这个接口是用来将对象序列化具体化的。如果你想定制自己的序列化机制 的话,它就派上用场了。它通过你自己编码的方式来完成对象的编解码。Externalizable接口继承了Serializable接口。如果你实现了这个接口你得重写下面的方法。
现在我们看下序列化是怎么进行的:
发送方:
JVM检查类是否实现了externalizable接口。如果实现了则使用writeExternal()方法来进行序列化。如果它没实现externalizable而实现了Serializable接口,就用ObjectOutputStream来进行对象的序列化。
接收方:
当对象被反序列化并且它实现了externalizable接口的话,就会用默认构造方法新建一个实例,然后调用它的readExternal方法。如果没有实现externalizable而实现了Serializable,就用ObjectOutputStream来进行对象的反序列化。
我们还是从Java的序列化中用到过的那个例子讲起。
在src->org.arpit.javapostsforlearning中新建一个Employee.java
如果实现了externalizable就必须有一个无参的构造方法。
在org.arpit.javapostsforlearning中新建一个ExternalizableMain.java。
运行:当你运行ExternalizableMain.java,你会得到这样的输出结果:
既然有了serializable,为什么还需要externalizable!
当你用serialize进行序列化时,除了所有字段,属于这个对象MAP的和成员变量能接触到的所有对象都会被序列化。比如:
如果你Employee有个父类是person,那么它会序列化所有的父类直到Object类。
同样的如果Employee有个address类型的成员变量,那么它会把整个address的整个对象集合也序列化进去。
如果你想序列化的只有employeeId和employeeName的话,你会希望增加这么多额外开销吗?
当你用serializable的话JVM会使用反射来进行序列化,这样会很慢。
当使用serializable时,类的描述信息也会存储到流里,包括父类的描述信息,和类关联的成员变量的信息。这也是一个性能问题。
外部序列化里的继承
我们现在来看下继承是怎么影响到外部序列化的。这里会有几种 情况比如 父类有没有实现过externalizable接口。如果没有你应该如何 处理,使得它能正常工作。我们来看个例子。
我们创建一个Employee的父类叫做Person。
场景1:如果父类没有实现externalizable:
如果父类没有实现externalizable,那么你得在实现externalizable的子类里序列化父类的字段。
在org.arpit.javapostsforlearning中创建Employee。
在org.arpit.javapostsforlearning新建ExternalizableMain。
运行后结果如下:
场景二:如果父类实现了Externalizable
如果父类实现了Externalizable,它也有相应的readExternal和writeExternal方法,它会用这些方法序列化自己的字段。
Person.java
Employee.java:
ExternalizableMain.java:
运行的结果:
在这个例子中,由于Person类用自己的writeExternal和readExternal方法存储和恢复自己的字段,不用再子类中序列化父类的字段。不过如果你仔细观察下Employee 的writeExternal和readExternal方法,你会发现还是先调了下super.xxxx方法,这样说明实现externalizable的对象还得和父类协作才能序列化对象的状态。
Externalizable的缺点:
如果你修改了类的定义,你得对应的修改writeExternal和readExternal方法。
就如示例中如示,子类对象必须 和父类进行协作才能正确存储和恢复自己的状态。
原创文章转载请注明出处:Java的Externalizable接口
英文原文链接