Java自定义序列化需实现Serializable接口,并声明private void writeObject(ObjectOutputStream)和private void readObject(ObjectInputStream)方法;JVM通过反射自动调用,必须严格匹配签名,先调defaultWriteObject()再手动处理额外字段,读写顺序须一致。

在 Java 中,可以通过实现 writeObject 和 readObject 方法来自定义对象的序列化逻辑,前提是该类实现了 Serializable 接口,并且这两个方法必须是 private void 签名、且参数分别为 ObjectOutputStream 和 ObjectInputStream。JVM 会在序列化/反序列化时自动调用它们,从而绕过默认机制。
自定义 writeObject 的基本写法
在类中声明一个 private void writeObject(ObjectOutputStream out) throws IOException 方法即可。注意:它不能是 static 或 final,也不能改变访问修饰符(必须是 private)。
- 必须先调用
out.defaultWriteObject()(如果还想保留默认字段序列化) - 之后可手动写入额外数据,比如计算值、临时状态、加密内容等
- 可以跳过某些字段(不调用
defaultWriteObject,完全自己控制)
常见使用场景与示例
比如有一个用户类,其中密码字段应避免明文序列化,或需要添加版本号、校验码:
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject(); // 序列化其他非瞬态字段
out.writeUTF(encrypt(password)); // 自定义写入加密后的密码
out.writeInt(VERSION); // 写入版本标识
}
对应地,readObject 必须严格按相同顺序读取:
立即学习“Java免费学习笔记(深入)”;
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
password = decrypt(in.readUTF());
int version = in.readInt(); // 校验或兼容处理
}
注意事项和限制
- 这两个方法只对当前类生效,不会自动作用于父类或子类(父类需自行实现)
- 若字段被标记为
transient,默认不会被defaultWriteObject处理,但你仍可在自定义逻辑中手动写入 - 不要在
writeObject中抛出未检查异常(如RuntimeException),否则会中断序列化流程 - 确保
readObject和writeObject的读写顺序、类型、数量完全一致,否则反序列化会失败
替代方案:Externalizable 接口
如果需要更彻底地控制序列化过程(比如完全跳过反射、提升性能或跨语言兼容),可实现 Externalizable 接口,重写 writeExternal 和 readExternal。此时 JVM 不会自动处理任何字段,全部由你负责。
- 必须提供 public 无参构造器(反序列化时会调用)
- 不再支持
transient或serialVersionUID的自动语义 - 适合对序列化格式有强约束的场景(如网络协议、存储格式)


















