transient仅对Java原生序列化有效,用于跳过指定字段;未实现Serializable接口时无效,第三方JSON库处理方式取决于框架配置而非JVM。

transient 只对 Java 原生序列化起作用
它不是“禁止序列化”的万能开关,而是 ObjectOutputStream / ObjectInputStream 在处理 Serializable 类时的过滤规则:跳过被 transient 修饰的字段。没实现 Serializable 接口?加了 transient 也毫无意义——根本不会触发序列化逻辑。
- 第三方 JSON 库(如 Jackson、FastJSON、Gson)默认通常忽略
transient字段,但这是框架自己的约定,不是 JVM 行为;你可以用@JsonProperty或@JSONField(serialize = true)强制让它参与 JSON 序列化 -
static字段本就不序列化,static transient是冗余写法,JVM 直接无视transient -
final transient字段反序列化后按类型默认值初始化(String→null,int→0),且无法在构造器中“补救”,因为反序列化不走构造器
哪些字段该加 transient?看三个硬标准
加 transient 不是凭感觉,而是满足以下任一条件:
- 不该持久化:密码、token、临时 session ID、密钥等敏感信息,明文落盘或跨网络传输等于裸奔
- 不能持久化:比如
Thread、InputStream、Connection等运行时资源,序列化后在另一 JVM 中必然失效,还会抛NotSerializableException - 不必持久化:缓存结果(
transient Map)、UI 组件引用、派生字段(如cache transient double totalPrice,可由price * qty重新计算)
反序列化后值丢了?别急着改字段,先看 readObject
transient 字段反序列化后一定是默认值(null / 0 / false),但你可以在类里自定义恢复逻辑:
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); // 先让 JVM 恢复非 transient 字段
this.password = "default_placeholder"; // 手动设值
this.cache = new HashMap<>(); // 重建不可序列化的对象
}- 必须是
private void readObject(ObjectInputStream)签名,且不能抛额外异常 - 务必调用
in.defaultReadObject(),否则非transient字段也不会恢复 - 如果用了
Externalizable,transient就完全失效——因为整个序列化流程你全权控制,JVM 不再自动判断字段是否跳过
常见踩坑:你以为它生效了,其实根本没走序列化
很多开发者调试时发现 transient 像没起作用,往往是因为:
立即学习“Java免费学习笔记(深入)”;
- 误把 Spring 的
@RequestBody/@ResponseBody当成原生序列化——那是 Jackson 在干活,transient默认有效,但若加了@JsonProperty就会覆盖它 - Redis 缓存用的是
JdkSerializationRedisSerializer(原生)才认transient;换成GenericJackson2JsonRedisSerializer后,行为由 Jackson 注解决定 - 字段是
final+transient,反序列化后值为null,但你又在 getter 里写了判空 fallback,导致误以为“它被恢复了”
真正关键的一点:transient 解决的是“要不要进字节流”,而不是“要不要进 JSON 字符串”或“要不要进数据库字段”。场景错配,再怎么加关键字也没用。










