Externalizable接口允许完全自定义序列化过程,需实现writeExternal和readExternal方法并提供无参构造器,所有字段必须显式读写,生成紧凑二进制流,但版本变更需手动处理兼容性。

在 Java 中使用 Externalizable 接口,可以完全控制对象的序列化和反序列化过程,绕过默认的 Serializable 机制。关键在于:你必须自己决定哪些字段写入、以什么顺序、用什么格式(如 int/short/UTF 字符串/自定义字节结构),并确保 readExternal 严格按相同逻辑读取。
实现 Externalizable 并重写两个方法
类需实现 Externalizable 接口(它继承自 Serializable),且必须提供一个 public 的无参构造器(反序列化时会调用)。然后重写:
- writeExternal(ObjectOutput out):手动把对象状态写成二进制流
- readExternal(ObjectInput in):从流中按相同顺序和类型读回状态
注意:Externalizable 不会自动保存任何字段(包括 transient 或非 transient),一切由你显式控制。
用 DataOutput 写出紧凑、可预测的二进制格式
ObjectOutput(如 DataOutputStream)提供了底层写入能力,适合构建自定义格式。例如:
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
public class Person implements Externalizable {
private String name;
private int age;
private boolean active;
// 必须有 public 无参构造器
public Person() {}
public Person(String name, int age, boolean active) {
this.name = name;
this.age = age;
this.active = active;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
// 自定义协议:先写 name 长度(short),再写 UTF-8 字节数组;再写 age(int);最后写 active(boolean)
if (name == null) {
out.writeShort(-1);
} else {
byte[] bytes = name.getBytes(StandardCharsets.UTF_8);
if (bytes.length > Short.MAX_VALUE) {
throw new IOException("Name too long");
}
out.writeShort((short) bytes.length);
out.write(bytes);
}
out.writeInt(age);
out.writeBoolean(active);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
short len = in.readShort();
if (len == -1) {
name = null;
} else {
byte[] bytes = new byte[len];
in.readFully(bytes);
name = new String(bytes, StandardCharsets.UTF_8);
}
age = in.readInt();
active = in.readBoolean();
}
}
这样生成的二进制流不带类名、字段名、类型描述等元数据,体积小、结构确定,适合跨语言解析或网络传输。
注意版本兼容与字段演进
因为格式完全自定义,Externalizable 对版本变更非常敏感:
- 新增字段?必须在
writeExternal末尾追加,并在readExternal中预留兼容逻辑(比如先读版本号,再分支处理) - 删除字段?要保留读取占位(否则后续字段错位),或引入协议版本字段
- 字段类型改了?比如
int改成long,必须同步更新读写逻辑,否则直接抛IOException
推荐在序列化开头写一个 byte protocolVersion = 1,后续所有字段解析都基于该版本分支处理,便于长期维护。
和 Serializable + writeObject 的区别
Externalizable 是“全权委托”模式;而 Serializable 中的 private void writeObject(ObjectOutputStream) 只是增强默认机制(仍会写类描述、字段名等头信息,且父类字段若未实现 Externalizable 仍走默认逻辑)。前者更轻量、更可控,后者更省事但不够干净。
如果追求极致二进制效率、协议稳定或需要跨平台解析,Externalizable 是合理选择;但日常开发中,多数场景用 Serializable 或现代替代方案(如 Protobuf、Jackson Binary)更稳妥。

















