重写writeObject方法可实现序列化时字段加密,核心是通过私有方法手动控制写入流程,对敏感字段先加密再写入;JVM优先调用匹配签名的private void writeObject(ObjectOutputStream)跳过默认反射逻辑;推荐AES/GCM等轻量对称加密,配合随机IV和Base64编码;需同步重写readObject保证解密正确性,且密钥不可硬编码、IV须随密文序列化。

重写 writeObject 方法实现序列化时字段加密,核心是在自定义的私有方法中手动控制对象写入流程,对敏感字段先加密再写入字节流。
理解 writeObject 的触发机制
Java 序列化默认会调用类中声明的私有方法 private void writeObject(ObjectOutputStream out) throws IOException,前提是该方法签名完全匹配且位于被序列化的类中。JVM 在序列化该对象时会优先使用它,跳过默认的反射写入逻辑。
加密前准备:选择轻量加密方式
序列化场景下不推荐使用重型算法(如 RSA),应选对称加密(如 AES)并确保密钥安全。常见做法:
- 使用固定密钥 + 随机 IV(每次加密生成新 IV,和密文一起写入)
- 采用 AES/GCM 模式兼顾加密与完整性校验(推荐),或 AES/CBC + 单独计算 HMAC
- 将加密后的字节数组转为 Base64 字符串存储(便于调试,但会增大体积)或直接写原始字节
重写 writeObject 的典型写法
以用户类 User 为例,对 password 字段加密:
private void writeObject(ObjectOutputStream out) throws IOException {
// 1. 先调用 defaultWriteObject 写入非敏感字段(或手动逐个 write)
out.defaultWriteObject();
// 2. 对敏感字段加密
String rawPassword = this.password;
byte[] encryptedBytes = encrypt(rawPassword); // 自定义加密方法
// 3. 写入加密后数据(建议同时写 IV 和密文)
out.writeInt(encryptedBytes.length);
out.write(encryptedBytes);
}
注意:defaultWriteObject() 会写入所有非 transient、非 static 字段(除 password 外)。若 password 声明为 transient,则必须手动写入,否则它不会出现在流中 —— 这是常见配合方式。
配套:必须重写 readObject 解密
序列化与反序列化需对称。若写了加密的 writeObject,就必须提供对应的 private void readObject(ObjectInputStream in),按相同顺序读取、解密并赋值:
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); // 读其他字段
int len = in.readInt();
byte[] encryptedBytes = new byte[len];
in.readFully(encryptedBytes);
this.password = decrypt(encryptedBytes); // 自定义解密方法
}
未配对实现会导致反序列化失败或字段为空。
不复杂但容易忽略:加密密钥不能硬编码在类里;IV 必须随密文一起序列化;加密异常需明确处理,避免静默失败。










