transient 仅在 java 原生序列化(objectoutputstream/objectinputstream)中生效,要求类实现 serializable 且字段为非 static、非 final 的实例变量;在 json、日志、数据库、http 等场景中完全无效。

transient 只在 Java 原生序列化(ObjectOutputStream/ObjectInputStream)中起作用,对 JSON、日志、数据库、HTTP 请求等完全无效。
哪些场景下 transient 真的会生效
它只在你显式调用 ObjectOutputStream.writeObject() 和 ObjectInputStream.readObject() 时才被 JVM 序列化机制识别。前提是类实现了 Serializable,且字段是实例变量(非 static、非 final)。
-
private transient String password;→ 反序列化后值为null -
private transient Date lastAccess;→ 反序列化后为null -
private static transient String token;→ 冗余写法,static字段本就不参与序列化 -
private final transient String salt;→ 编译通过但语义混乱;final字段若已在构造器中赋值,仍可能被序列化,加transient不解决根本问题
为什么加了 transient 还在 JSON 响应里看到密码
因为 Spring Boot 默认用 Jackson,而 Jackson 完全不认 transient —— 它走的是反射+注解路径,不是 JDK 原生序列化流程。
- Jackson:必须用
@JsonIgnore或全局配置MapperFeature.USE_ANNOTATIONS - Gson:默认忽略
transient,需显式启用:new GsonBuilder().excludeFieldsWithModifiers(Modifier.TRANSIENT) - Fastjson:用
@JSONField(serialize = false) - Spring
@RequestBody绑定、JPA 实体转 JSON、MyBatis 返回对象 → 全部绕过transient
常见误用和真正危险的坑
加了 transient 就以为“密码安全了”,这是最典型的认知偏差。它既不防日志,也不防内存 dump,更不防网络明文传输。
-
toString()方法照常打印password→ 必须重写,跳过敏感字段 - 调试器、heap dump、JFR 录制中仍可见明文 → 敏感字段建议用
char[],用完立即Arrays.fill(pwd, '\0') - 自定义
writeObject()中手动写了out.writeUTF(password)→transient被绕过 - 把
User实体直接当 DTO 返回给前端 → 即使加了transient,其他字段也可能暴露业务逻辑或关联 ID
真正关键的不是“怎么加 transient”,而是分清数据所处的上下文:网络层用 DTO 隔离,存储层加密,日志层脱敏,序列化层按需选注解或白名单。原生 transient 只是一条狭窄通道上的单向闸门,别把它当成整面墙。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











