* * @author unascribed * @see java.io.ObjectOutputStream * @see java.io.ObjectInputStream * @see java.io.ObjectOutput * @see java.io.ObjectInput * @see java.io.Serializable * @since JDK1.1 */ public interface Externalizable extends java.io.Serializable { /** * The object implements the writeExternal method to save its contents * by calling the methods of DataOutput for its primitive values or * calling the writeObject method of ObjectOutput for objects, strings, * and arrays. * * @serialData Overriding methods should use this tag to describe * the data layout of this Externalizable object. * List the sequence of element types and, if possible, * relate the element to a public/protected field and/or * method of this Externalizable class. * * @param out the stream to write the object to * @exception IOException Includes any I/O exceptions that may occur */ void writeExternal(ObjectOutput out) throws IOException; /** * The object implements the readExternal method to restore its * contents by calling the methods of DataInput for primitive * types and readObject for objects, strings and arrays. The * readExternal method must read the values in the same sequence * and with the same types as were written by writeExternal. * * @param in the stream to read data from in order to restore the object * @exception IOException if I/O errors occur * @exception ClassNotFoundException If the class for an object being * restored cannot be found. */ void readExternal(ObjectInput in) throws IOException, ClassNotFoundException; }
Externalizable接口是Serializable接口的子接口,在此接口中定义了两个方法,这两个方法的作用如下。
writeExternal(ObjectOutput out):在此方法中指定要保存的属性信息,对象序列化时调用。
readExternal(ObjectInput in):在此方法中读取被保存的信息,对象反序列化时调用。
这两个方法的参数类型是ObjectOutput和ObjectInput,两个接口的定义如下。
ObjectOutput接口定义:
public interface ObjectOutput extends DataOutput
ObjectInput接口定义:
public interface ObjectInput extends DataInput
可以发现以上两个接口分别继承DataOutput和DataInput,这样在这两个方法中就可以像DataOutputStream和DataInputStream那样直接输出和读取各种类型的数据。
如果一个类要使用Externalizable实现序列化时,在此类中必须存在一个无参构造方法,因为在反序列化时会默认调用无参构造实例化对象,如果没有此无参构造,则运行时将会出现异常,这一点的实现机制与Serializable接口是不同的。
import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; public class Person implements Externalizable { private String name; private int age; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } public String toString() { // 覆写toString()方法 return "姓名:" + this.name + ";年龄:" + this.age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } // 覆写此方法,根据需要可以保存属性或具体内容, 序列化时使用 @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(this.name) ; // 保存姓名属性 out.writeInt(this.age) ; // 保存年龄属性 } //// 覆写此方法,根据需要读取内容,反序列化时使用 @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { this.name = (String)in.readObject() ; // 读取姓名属性 this.age = in.readInt() ; } }
以上程序中的Person类实现了Externalizable接口,这样用户就可以在类中有选择地保存需要的属性或者其他的具体数据。在本程序中,为了与之前的程序统一,将全部属性保存下来。
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; public class SerDemo03 { public static void main(String[] args) throws Exception { ser(); // 序列化 dser(); // 反序列化 } public static void ser() throws Exception { // 序列化操作 File f = new File("D:" + File.separator + "test.txt"); ObjectOutputStream oos = null; OutputStream out = new FileOutputStream(f); // 文件输出流 oos = new ObjectOutputStream(out); // 为对象输出流实例化 oos.writeObject(new Person("张三", 30)); // 保存对象到文件 oos.close(); // 关闭输出 } public static void dser() throws Exception { // 反序列化操作 File f = new File("D:" + File.separator + "test.txt"); ObjectInputStream ois = null; InputStream input = new FileInputStream(f); // 文件输出流 ois = new ObjectInputStream(input); // 为对象输出流实例化 Object obj = ois.readObject(); // 读取对象 ois.close(); // 关闭输出 System.out.println(obj); } }
从以上代码中可以发现,使用Externalizable接口实现序列化明显要比使用Serializable接口实现序列化麻烦得多,除此之外,两者的实现还有不同,如表12-27所示。
表12-27 Externalizable接口与Serializable接口实现序列化的区别
序 号 |
区 别 |
Serializable |
Externalizable |
1 |
实现复杂度 |
实现简单,Java对其 有内建支持 |
实现复杂, 由开发人员自己完成 |
2 |
执行效率 |
所有对象由Java统一保存, 性能较低 |
开发人员决定哪个对象保存, 可能造成速度提升 |
3 |
保存信息 |
保存时占用空间大 |
部分存储, 可能造成空间减少 |
在一般的开发中,因为Serializable接口的使用较为方便,所以出现较多
相比Serializable,Externalizable序列化的速度更快,序列化之后的数据更小,但读和取都需要开发人员自行实现;
Serializable开发相对简单,速度慢,序列化后的数据更大些。
这两种序列化方式都有一个特点,如果多个对象a的内部属性b同时指向同一个对象,即同时引用了另外一个对象b。序列化->反序列化之后,这几个对象属性还是会同时指向同一个对象b,不会反序列化出多个b对象。
但是,如果多个对象a是多次被序列化的,在反序列后对象b会被反序列化多次,即多个a对象的属性b是不一样的。
Serializable是整个对象的序列化,不管需不需要,这个过程不需要我们来设计实现。
Externalizable是对对象有选择的进行序列化,根据业务的需要对相应的属性实现序列化,并且这个过程需要我们自己来实现。
感觉有点像hibernate与ibatis...