Externalizable接口实现完全自定义序列化,需显式实现接口、提供public无参构造器,并重写writeExternal与readExternal方法,字段读写完全由开发者控制,支持精细版本兼容。

Externalizable 接口让你彻底接管序列化过程,不是“增强 Serializable”,而是完全重写对象怎么存、怎么读。它不自动处理任何字段,也不依赖反射,所有逻辑由你手写。
必须满足三个硬性条件
缺一不可,否则运行时直接报错:
- 类要显式 implements Externalizable(不能只实现 Serializable)
- 必须提供一个 public 无参构造器——反序列化时 JVM 先调它创建空对象,再进 readExternal
- 必须重写 writeExternal 和 readExternal 两个方法,一个都不能少
writeExternal:只写你需要的字段
你在里面调用 out.writeXXX() 写什么,字节流里就有什么;不写,就彻底消失,连字段名、类型描述都不占空间。
- 跳过 transient 或 static 字段?不用声明,不写就行
- 忽略计算属性(如 getFullName())、缓存 Map、临时状态(如 isSaving)?直接不调用对应 write 方法
- 可主动加版本号:out.writeInt(2),为后续兼容留余地
- 敏感字段(如 token、passwordHash)只要不写,就不会出现在序列化数据中——transient 在这里完全无效
readExternal:必须和 writeExternal 严格镜像
读的顺序、类型、次数,必须和写的完全一致。错一位或混一个类型,运行时立刻抛 StreamCorruptedException 或 ClassCastException。
立即学习“Java免费学习笔记(深入)”;
- 先写 int id,就得先读 id = in.readInt()
- 再写 String name,就得紧跟着读 name = in.readUTF()
- 如果开头写了版本号,就必须先读 int version = in.readInt(),再按 version 分支决定后续读哪些字段
- 父类也实现了 Externalizable?子类 readExternal 中得显式调用 super.readExternal(in)
和 Serializable 的本质区别
Serializable 是“告诉 JVM 可以序列化”,JVM 自动递归处理非 transient 字段;Externalizable 是“我来干全部活”,JVM 只负责调构造器和两个方法,其余一切归你。
- 没有默认字段扫描,没有元数据开销,性能更高、体积更小
- 没有 serialVersionUID,版本控制靠你手动加版本号+分支逻辑
- 没有 writeObject/readObject 钩子,也没有 defaultWriteObject/defaultReadObject 调用
- 安全性更强——你不写的数据,永远进不了字节流


















