Externalizable接口要求彻底接管序列化:必须提供public无参构造器,writeExternal仅写需持久化字段,readExternal严格镜像读取,跳过元数据与无关字段以提升性能。

Java 中使用 Externalizable 接口不是“给 Serializable 加个补丁”,而是彻底换一条路:你放弃 JVM 自动序列化的所有默认行为,亲手控制每个字节的写入和读取。
必须提供 public 无参构造器
反序列化时,JVM 会先用反射调用这个构造器创建空对象,再执行 readExternal 填充字段。缺它直接抛 NoSuchMethodException。
- 构造器可以为空,但不能省略
- 可在其中设默认值(如
status = ACTIVE),但此时所有字段仍是初始值(null/0/false) - 不要在构造器里依赖未恢复的字段做判断或远程初始化
- 若父类也实现了
Externalizable,子类构造器无需特殊处理,但readExternal中必须显式调用super.readExternal(in)
writeExternal 只写真正需要持久化的字段
这里没有自动跳过 transient 或 static 字段的机制——你没写,它就彻底不出现在字节流中,连字段名和类型描述都不占空间。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 跳过运行时计算字段(如
getFullName())、缓存字段(如cacheMap)、临时状态(如isProcessing) - 可主动加入轻量元信息,例如开头写版本号:
out.writeInt(1),后续按版本分支读取 - 敏感字段(如
passwordHash、apiToken)只要不调用out.writeXXX(),就不会进序列化流——transient在这里完全无效
readExternal 必须与 writeExternal 严格镜像
这不是建议,是硬性契约。读的顺序、类型、次数,必须和写的完全一致。错一位、混一个类型,就会在运行时炸开(StreamCorruptedException 或 ClassNotFoundException)。
立即学习“Java免费学习笔记(深入)”;
- 例如
writeExternal写了:out.writeInt(id); out.writeUTF(name); out.writeBoolean(active); - 那么
readExternal就必须严格按此顺序、此类型读:id = in.readInt(); name = in.readUTF(); active = in.readBoolean(); - 如果写了版本号,读时先
int version = in.readInt();,再根据version决定后续读哪些字段、是否跳过废弃字段 - 引用类型(如
List<String>)用in.readObject()读,前提是写入时也用了out.writeObject()
适用场景要足够明确
Externalizable 不适合日常开发中的简单对象。它面向的是对性能、带宽、安全性有极致要求的系统。
- 典型场景:高频交易系统、实时游戏服务器、自定义二进制协议、大规模缓存中间件(如 Redis 存储玩家快照)
- 必须有明确性能测试支撑:确认默认序列化已成为瓶颈,且优化后 QPS 或 P99 延迟有显著改善
- 优先考虑现代替代方案:如 Protobuf、Kryo 或 Jackson Binary,它们更安全、易维护,且多数场景下性能不输甚至更优

















