要通过Externalizable接口实现完全自定义序列化,必须显式实现接口、提供public无参构造器,并重写writeExternal和readExternal方法;字段全由开发者手动控制读写,顺序与类型必须严格一致,且父类需显式调用super方法。

要通过 Externalizable 接口实现 Java 对象的完全自定义序列化,关键不是“补充默认行为”,而是彻底接管整个流程——从对象创建、字段选择,到字节写入与读回,全部由你编码控制。
必须满足三个硬性前提
缺一不可,否则运行时直接报错:
- 类显式声明
implements Externalizable(不能只实现Serializable) - 提供 public 无参构造器:反序列化时 JVM 会先调用它创建空实例,再进
readExternal - 重写
writeExternal(ObjectOutput out)和readExternal(ObjectInput in)两个方法
字段控制权 100% 归你
Externalizable 不自动处理任何字段,哪怕它是 public、非 transient、甚至来自父类。你写什么,才存什么;你读什么、怎么读,对象就怎么恢复。
- 在
writeExternal中,只调用out.writeXXX()写你需要持久化的字段,比如:out.writeUTF(name); out.writeInt(id); out.writeBoolean(active); - 跳过计算字段(如
getFullName())、缓存字段(如cacheMap)、敏感字段(如token),只要不写,就彻底不出现在字节流里 - 可以主动加元信息,例如开头写版本号:
out.writeInt(2);,为后续兼容升级留空间
读写顺序和类型必须严格镜像
这不是建议,是强制契约。错一位、混一个类型,就会抛 StreamCorruptedException 或类型转换异常。
- 如果
writeExternal先写int、再写String、最后写boolean,那么readExternal必须按相同顺序、相同类型读:id = in.readInt(); name = in.readUTF(); active = in.readBoolean(); - 若加了版本号,读时必须最先读:
int version = in.readInt();,再根据version分支决定后续读哪些字段、是否跳过已废弃字段 - 有父类且父类也实现了
Externalizable,子类的readExternal需显式调用super.readExternal(in),writeExternal同理
相比 Serializable 的核心差异
Externalizable 不是“增强版 Serializable”,而是另一条技术路径:
-
Serializable自动递归保存非transient字段,带大量元数据(类名、字段名等),性能低、体积大、安全性弱 -
Externalizable无反射开销、无元数据冗余、无默认字段遍历,体积更小、速度更快、控制粒度更细 - 没有
serialVersionUID机制,版本兼容靠你在读写逻辑中自行设计(如版本号 + 条件分支) -
transient关键字在这里完全失效——是否序列化,只取决于你是否在writeExternal中调用写方法
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











