源码:
package java.io;
import java.io.ObjectOutput;
import java.io.ObjectInput;
public interface Externalizable extends java.io.Serializable {
void writeExternal(ObjectOutput out) throws IOException;
void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}
Implements: Serializable
Implemented by: DataFlavor, MimeType, MLet, RemoteRef
Externalizable 实例类的唯一特性是可以被写入序列化流中,该类负责保存和恢复实例内容。若某个要完全控制某一对象及其超类型的流格式和内容,则它要实现 Externalizable 接口的 writeExternal 和 readExternal 方法。这些方法必须显式与超类型进行协调以保存其状态。这些方法将代替定制的 writeObject 和 readObject 方法实现。
Serialization 对象将使用 Serializable 和 Externalizable 接口。对象持久性机制也可以使用它们。要存储的每个对象都需要检测是否支持 Externalizable 接口。如果对象支持 Externalizable,则调用 writeExternal 方法。如果对象不支持 Externalizable 但实现了 Serializable,则使用 ObjectOutputStream 保存该对象。
在重构 Externalizable 对象时,先使用无参数的公共构造方法创建一个实例,然后调用 readExternal 方法。通过从 ObjectInputStream 中读取 Serializable 对象可以恢复这些对象。
Externalizable 实例可以通过 Serializable 接口中记录的 writeReplace 和 readResolve 方法来指派一个替代对象。
readExternal(ObjectInput in) throwsIOException, ClassNotFoundException
对象实现 readExternal 方法来恢复其内容,它通过调用 DataInput 的方法来恢复其基础类型,调用 readObject 来恢复对象、字符串和数组。readExternal 方法必须按照与 writeExternal 方法写入值时使用的相同顺序和类型来读取这些值。
in |
为了恢复对象而从中读取数据的流 |
Throws |
IOException:
如果发生 I/O 错误 |
Throws |
ClassNotFoundException:
如果无法找到需要恢复的某个对象的类。 |
writeExternal( ObjectOutput out) throws IOException
对象可实现 writeExternal 方法以保存其内容,它可以通过调用 DataOutput 的方法来保存其基本值,或调用 ObjectOutput 的 writeObject 方法来保存对象、字符串和数组。
serialData |
重写方法时应使用该标记来描述此 Externalizable 对象的数据布局。列出元素类型的顺序,如有可能,将元素与某一公共/受保护字段和/或此 Externalizable 类的方法相关联。 |
out |
要将对象写入的流 |
Throws |
IOException:
包含可能发生的所有 I/O 异常 |
这两个方法的参数类型是ObjectOutput和ObjectInput,两个接口的定义如下。
ObjectOutput接口定义:
- public interface ObjectOutput extends DataOutput
ObjectInput接口定义:
- public interface ObjectInput extends DataInput
可以发现以上两个接口分别继承DataOutput和DataInput,这样在这两个方法中就可以像DataOutputStream和DataInputStream那样直接输出和读取各种类型的数据。
如果一个类要使用Externalizable实现序列化时,在此类中必须存在一个无参构造方法,因为在反序列化时会默认调用无参构造实例化对象,如果没有此无参构造,则运行时将会出现异常,这一点的实现机制与Serializable接口是不同的。
范例:修改Person类并实现Externalizable接口
- package org.lxh.demo12.serdemo;
- import java.io.Externalizable;
- import java.io.IOException;
- import java.io.ObjectInput;
- import java.io.ObjectOutput;
- public class Person implements Externalizable {// 此类的对象可以被序列化
- private String name; // 声明name属性
- private int age; // 声明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 void readExternal(ObjectInput in) throws IOException,
- ClassNotFoundException {
- this.name = (String)in.readObject() ; // 读取姓名属性
- this.age = in.readInt() ; // 读取年龄
- }
- // 覆写此方法,根据需要可以保存属性或具体内容,序列化时使用
- public void writeExternal(ObjectOutput out) throws IOException {
- out.writeObject(this.name) ; // 保存姓名属性
- out.writeInt(this.age) ; // 保存年龄属性
- }
- }
以上程序中的Person类实现了Externalizable接口,这样用户就可以在类中有选择地保存需要的属性或者其他的具体数据。在本程序中,为了与之前的程序统一,将全部属性保存下来。
范例:序列化和反序列化Person对象
- package org.lxh.demo12.serdemo;
- 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接口的使用较为方便,所以出现较多