Java序列化中通过重写private void writeObject(ObjectOutputStream)可手动控制字段写入流程,替代默认反射机制;需实现Serializable接口,配合defaultWriteObject()与自定义写入,并对称实现readObject()完成反序列化。

必须满足的基本前提
该机制不是“增强”而是“替代”:一旦声明了匹配的 private void writeObject,JVM 就不再走默认字段遍历逻辑。
- 方法必须是 private、非 static、非 final,且参数类型严格为
ObjectOutputStream - 类仍需实现
Serializable接口(否则连进入该流程的机会都没有) - 若父类也有自定义逻辑,子类需显式调用父类对应方法(
super.writeObject(out)不生效,得手动处理)
典型写法:混合默认 + 手动控制
多数场景下,不需要从零写所有字段。常用模式是先调用 defaultWriteObject() 保留普通字段,再单独处理敏感或特殊字段。
-
out.defaultWriteObject()写入所有非transient、非static字段(除已标记为 transient 的) - 对
transient字段(如密码、缓存),在之后手动加密、转换或跳过 - 写入顺序必须与后续
readObject中的读取顺序严格一致
例如:
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject(); // 先写 name、age 等常规字段
out.writeUTF(encrypt(password)); // 单独加密写 password
out.writeLong(System.currentTimeMillis()); // 补充时间戳
}
进阶控制:完全接管字段选择与格式
如果不想依赖 defaultWriteObject(),也可以彻底放弃它,逐个决定每个字段是否写、怎么写、写成什么形式。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
- 不声明任何
transient,但只在writeObject中显式调用out.writeXXX()需要的字段 - 可写入额外元数据,比如版本号、校验和、压缩标识等
- 支持跨版本兼容:例如老版本只写 name,新版本加写 email,反序列化时按版本分支读取
配套必须实现 readObject
写入流程变了,读取流程也必须对称。否则会因字段缺失或类型错位抛出 IOException 或 ClassNotFoundException。
- 同样要求 private、签名匹配
- 先调用
in.defaultReadObject()恢复常规字段,再按相同顺序读取自定义部分 - 解密、重建 transient 字段(如数据库连接、线程局部变量等)都放在这里
示例:
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
this.password = decrypt(in.readUTF());
this.createdAt = in.readLong();
}

















