transient是java原生序列化的语言级字段排除机制,仅在类实现serializable且字段为非static非final实例变量时生效,反序列化后恢复默认值;对json、jpa、日志等场景无效。

在 Java 原生序列化中,transient 是唯一由 JVM 直接识别、用于跳过字段序列化的语言级机制。但它只在 ObjectOutputStream.writeObject() 和 ObjectInputStream.readObject() 场景下起作用,且必须满足前提条件。
生效的前提和写法
要让 transient 正常工作,必须同时满足:
- 类实现
Serializable接口(不能是Externalizable) - 目标字段是**非 static、非 final 的实例变量**
- 未自定义
writeObject()或在其中手动写入该字段
写法很简单,在字段声明前加关键字即可:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
private String username; private transient String password; // 反序列化后为 null private transient int loginCount; // 反序列化后为 0
它真正能挡住什么
transient 仅影响 Java 原生序列化字节流的生成与还原过程:
- 对象写入文件(
FileOutputStream → ObjectOutputStream)时,被标记字段不进入字节流 - 通过 Redis、RMI、本地缓存等依赖原生序列化的场景,该字段不会落盘或传输
- 反序列化后,字段值恢复为类型默认值(引用类型为
null,基本类型为0/false)
它完全挡不住的常见场景
很多开发者误以为加了 transient 就“安全了”,其实以下情况它完全无效:
-
JSON 响应:Spring Boot 的
@ResponseBody默认用 Jackson,无视transient;需改用@JsonIgnore或开启MapperFeature.USE_TRANSIENT_ANNOTATION -
数据库操作:JPA/Hibernate 是否持久化某字段,取决于
@Column或@Transient注解,和transient关键字无关 -
日志和调试:
toString()、IDE 调试器、heap dump 中仍可直接看到明文;敏感字段建议用char[]并及时清空 -
HTTP 绑定:Spring 的
@RequestBody是反射赋值,不走序列化流程,transient不起作用
更可靠的替代或补充方式
单靠 transient 已无法满足现代应用的安全要求,推荐分层控制:
-
DTO 隔离:返回给前端的对象(如
UserResponse)根本不声明password字段 -
序列化专用注解:Jackson 用
@JsonIgnore,Fastjson 用@JSONField(serialize = false),Gson 用@Expose(serialize = false) - 存储层防护:密码必须哈希加盐后入库,内存中避免长期持有明文字符串
-
构建时检查:CI 流程中用 SpotBugs 检测
Serializable类中未处理的敏感字段
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










