externalizable接口通过手动实现writeexternal和readexternal方法并提供public无参构造器,完全控制序列化过程;不自动保存任何字段,读写顺序与类型必须严格一致,适用于精简、加密或协议定制场景。

Java 中外部序列化(Externalizable)通过自定义 writeExternal 和 readExternal 方法实现完全控制序列化过程,绕过默认的反射机制,比 Serializable 更灵活、更高效,也更适合版本兼容或敏感字段处理。
实现 Externalizable 接口的基本要求
类必须显式实现 java.io.Externalizable 接口,并提供一个 public 无参构造器(反序列化时会通过反射调用它)。接口只声明两个方法,不继承任何默认行为:
-
public void writeExternal(ObjectOutput out) throws IOException:手动指定哪些字段写入流 -
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException:按相同顺序、类型从流中读回字段
手动控制字段序列化与反序列化
你决定每个字段是否保存、以什么格式保存(如压缩、加密、转换类型),甚至可以跳过 transient 字段或添加运行时计算值。例如:
public class User implements Externalizable {
private String name;
private int age;
private transient String password; // 不序列化原始密码
public User() {} // 必须有!反序列化时调用
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(name != null ? name : "");
out.writeInt(age);
out.writeUTF(encrypt(password)); // 自定义加密后写入
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
name = in.readUTF();
age = in.readInt();
password = decrypt(in.readUTF()); // 对应解密读取
}
}
注意:writeExternal 和 readExternal 的字段顺序和类型必须严格一致,否则反序列化会抛出 IOException 或数据错乱。
处理版本兼容与可选字段
Externalizable 不自动处理字段增减。如需向后兼容,可在流中写入版本号,再根据版本分支读取逻辑:
- 首次写入:
out.writeInt(1); - 后续升级类增加字段时,在
writeExternal中先写版本号,再按版本写不同字段集 -
readExternal先读版本号,再用 if/else 分支加载对应字段
这种方式比 serialVersionUID + defaultReadObject 更可控,但需开发者自行维护协议。
与 Serializable 的关键区别
Externalizable 完全放弃 JVM 默认序列化逻辑:
- 不检查
transient关键字——你写就写,不写就不写 - 不调用父类的序列化(除非你主动在
writeExternal中处理) - 不生成或校验
serialVersionUID(但建议仍声明,便于调试和工具识别) - 性能更高(避免反射开销),体积更小(无字段元信息)
适合对序列化格式有强约束的场景,比如跨语言通信中间格式、安全敏感的数据持久化、或高频网络传输对象。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











