externalizable接口要求完全手动控制序列化:必须提供public无参构造器,writeexternal显式写出所需字段,readexternal严格按相同顺序和类型读取,父子类需显式调用super方法,不依赖transient或serialversionuid,适用于精简、加密或协议定制场景。

Externalizable 接口让你彻底接管序列化过程——不自动保存任何字段,也不依赖默认机制。关键在于你显式决定哪些变量参与、怎么写、怎么读,且顺序和类型必须严丝合缝。
必须提供 public 无参构造器
反序列化时 JVM 会调用它来创建对象实例,哪怕你平时只用有参构造器,也得补上这个空构造器。初始化逻辑(比如设置默认值、注册监听)可以放在这里,但注意:它会在 readExternal 执行前被调用,所以字段还都是初始状态(null / 0 / false)。
writeExternal 中只写你需要的变量
你在里面调用 out.writeXXX() 的每一个操作,都对应未来反序列化时的一次读取。可以跳过 transient 字段、计算字段、缓存字段,甚至加写版本号或时间戳。
- 例如只持久化核心业务数据:
out.writeInt(id); out.writeUTF(name); out.writeBoolean(active); - 不要写
createTime(由构造器或数据库生成),也不要写cacheMap(运行时重建即可) - 若需兼容旧版本,开头写入
out.writeInt(2);,后续按版本分支处理字段读取
readExternal 必须与 writeExternal 完全镜像
读的顺序、类型、数量,必须和写的完全一致。少读一个、多读一个、类型错位(比如该读 int 却调用 readUTF),都会直接抛 StreamCorruptedException 或 ClassNotFoundException。
- 严格按顺序还原:
id = in.readInt(); name = in.readUTF(); active = in.readBoolean(); - 如果父类也实现了 Externalizable,子类的
readExternal中必须显式调用super.readExternal(in),否则父类字段不会恢复 - 敏感字段如密码、token,只要不在
writeExternal中写出,就不会进序列化流——transient在这里不起作用,纯靠你手动省略
它不是 Serializable 的升级版,而是另一条路
Externalizable 不继承 Serializable 的任何行为,连 serialVersionUID 都不生效。它适合需要精简体积、加密压缩、对接二进制协议、或绕过默认递归开销的场景。但代价是:所有逻辑你负责,所有兼容性你兜底。










