是的,transient字段在默认Java序列化中被跳过,反序列化后为默认值;但自定义writeObject/readObject、非标准框架(如Jackson)或Externalizable接口下该修饰符可能失效。

transient字段在序列化时真的被跳过了吗
是的,transient修饰的字段在默认Java序列化(即实现Serializable接口 + ObjectOutputStream.writeObject())中**不会被写入字节流**,反序列化时该字段值为对应类型的默认值(如null、0、false)。但这仅适用于“默认序列化流程”,不涉及自定义writeObject()或readObject()方法的情况。
常见误判场景:
- 字段被
transient修饰,但类里手动写了private void writeObject(ObjectOutputStream out) throws IOException,并在其中显式调用了out.defaultWriteObject()之后又out.writeObject(myField)——此时该字段仍会被序列化 - 使用了非标准序列化框架(如Jackson、FastJSON、Kryo),它们**完全不识别
transient关键字**,是否忽略取决于各自的注解或配置(如Jackson用@JsonIgnore)
为什么static字段不用加transient也能跳过
static字段本就不属于对象实例状态,而Java序列化只保存**对象实例的非静态成员变量**。因此static字段天然不参与序列化,加不加transient效果一样,但编译器允许你加——只是冗余操作,无实际作用。
注意:transient和static语义完全不同:static表示类级别共享;transient表示“这个实例字段我不希望它被序列化”,哪怕它是实例变量。
立即学习“Java免费学习笔记(深入)”;
示例对比:
public class User implements Serializable {
private static String version = "1.0"; // 不会序列化(static)
private transient String token; // 不会序列化(transient)
private String name; // 会被序列化
}
transient字段反序列化后怎么恢复业务逻辑
如果字段需要在反序列化后重新初始化(比如缓存、连接、临时计算结果),不能依赖构造函数(反序列化不走构造器),必须通过readObject()钩子方法手动处理。
典型做法:
- 声明
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException - 第一行必须调用
in.defaultReadObject(),否则非transient字段也不会被恢复 - 之后可对
transient字段赋值,例如从配置重建、调用初始化方法、或设为默认值
示例:
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); // 先恢复所有非transient字段
this.token = generateNewToken(); // 手动重建transient字段
}
transient和Externalizable接口能混用吗
可以,但意义不大。Externalizable要求你**完全接管序列化逻辑**,实现writeExternal()和readExternal()。此时transient关键字会被彻底忽略——因为你不调用defaultWriteObject(),所有字段是否写入全由你代码决定。
容易踩的坑:
- 实现
Externalizable却忘了在writeExternal()里写某个关键字段,导致反序列化后对象状态残缺 - 误以为加了
transient就能省事,结果在writeExternal()里漏写了它,反而造成逻辑断裂 -
Externalizable的反序列化构造器必须是public且无参的,否则运行时报InvalidClassException
简单说:选Externalizable就别依赖transient做控制,它已退场。










