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

Java 实现 Externalizable 接口不是“微调 Serializable”,而是彻底接管序列化流程——通过手动控制字段读写、跳过元数据和无关状态,实现真正的性能提升。关键不在于重写方法,而在于精准裁剪。
必须补上 public 无参构造器
反序列化时 JVM 会强制调用该构造器创建空实例,再执行 readExternal 填充字段。缺它直接抛 NoSuchMethodException。
- 构造器可以为空,但不能省略;也可设默认值(如
status = ACTIVE),但此时所有字段仍是初始值(null/0/false) - 不要在构造器里依赖未恢复的字段做逻辑判断或远程初始化
- 若父类也实现 Externalizable,子类构造器无需特殊处理,但
readExternal中必须显式调用super.readExternal(in)
writeExternal 只写真正需要持久化的字段
这里没有自动排除 transient 或 static 字段的机制——你没写,它就彻底不存在于字节流中,连字段名和类型描述都不占一个字节。
Java开发手册规约集合,基于阿里巴巴Java开发手册(嵩山版)。 涵盖7大维度:编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约。 当用户需要:(1) 编写或审查Java代码 (2) 检查命名/代码规范 (3) 处理异常和日志 (4) 编写单元测试 (5) 安全编码 (6) 数据库设...
- 跳过运行时计算字段(如
getFullName())、缓存字段(如cacheMap)、临时状态(如isProcessing) - 可主动加入轻量元信息:开头写版本号
out.writeInt(1),后续按版本分支读取,便于兼容升级 - 敏感字段(如
passwordHash、apiToken)只要不调用out.writeXXX(),就不会出现在流中——transient在此完全无效,也不需加
readExternal 必须与 writeExternal 严格镜像
这不是建议,是硬性契约。读的顺序、类型、次数,必须和写的完全一致。错一位、混一个类型,就会在运行时炸开(StreamCorruptedException 或 ClassNotFoundException)。
- 例如
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决定后续读哪些字段、是否跳过废弃字段
适用场景与使用前提
Externalizable 不适合日常开发中的简单对象,它面向的是对性能、带宽、安全性有极致要求的系统。
- 典型场景:高频交易系统、实时游戏服务器、自定义二进制协议、大规模缓存中间件(如 Redis 存储玩家快照)
- 必须有明确性能测试支撑:确认默认序列化成为瓶颈,且优化后 QPS/P99 延迟有显著改善
- 优先考虑现代替代方案:如 Protobuf、Kryo 或 Jackson Binary,它们更安全、易维护,且多数已内置版本兼容与字段控制能力
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










