反射是gson、jackson等json框架的底层支柱,通过运行时获取类结构实现对象与json互转:序列化时扫描字段、读取值并选择序列化器;反序列化时创建实例、映射字段并赋值;其通用性依赖反射对class对象和注解的动态解析。

反射是 Gson、Jackson 这类 JSON 框架的底层支柱,它们不靠编译期硬编码,而是靠运行时“看懂”类结构来完成对象与 JSON 的互转。
反射如何支撑序列化(Java → JSON)
当调用 mapper.writeValueAsString(user) 时,Jackson 并不知道 User 类里有几个字段、类型是什么、要不要忽略某个字段。它通过反射做这几件事:
- 用
User.class.getDeclaredFields()扫描所有字段(包括 private 字段),获取字段名、类型、注解(如@JsonProperty、@JsonIgnore) - 对每个字段,用
field.setAccessible(true)绕过访问限制,再调用field.get(user)读取值 - 根据字段类型(String、int、List 等)选择对应的序列化器(Serializer),比如
StringSerializer或自定义的日期格式器 - 把字段名和序列化后的值组装成键值对,写入 JSON 输出流
反射如何支撑反序列化(JSON → Java)
当执行 mapper.readValue(json, User.class) 时,Jackson 需要从 JSON 字符串中提取数据,并填充到一个 User 实例中。这个过程依赖反射完成:
- 先用
Class.forName("com.example.User")或直接传入的User.class获取 Class 对象 - 查找匹配的构造器(默认无参构造器,或带
@JsonCreator注解的构造器),用constructor.newInstance()创建空实例 - 解析 JSON 中的 key(如
"name"),通过clazz.getDeclaredField("name")找到对应字段;若字段名不一致,就用@JsonProperty("userName")做映射 - 对每个字段调用
field.setAccessible(true),再用field.set(instance, value)赋值 - 如果字段是嵌套对象或集合,递归触发相同流程——整个过程由反射驱动的类型导航完成
为什么 Gson 和 Jackson 都离不开反射
这两个库的设计目标是“零侵入”或“低侵入”:你不用为每个类手写序列化逻辑,也不用提前注册所有类型。这种通用性只有靠反射才能实现:
- 它们不依赖源码,只依赖已加载的 Class 对象和字节码信息
- 能自动适配新增字段、修改访问修饰符、响应注解配置,无需重新编译框架代码
- 支持泛型擦除后的类型还原(如
List<user></user>),靠的是TypeReference+ 反射获取的ParameterizedType信息 - Gson 的
FieldNamingPolicy、Jackson 的PropertyNamingStrategies等命名策略,都是在反射获取字段名后做字符串转换
实际开发中需要注意的点
反射虽强大,但不是黑盒魔法。理解它的工作方式,能帮你避开常见问题:
- 无参构造器是默认要求:若类没有 public 无参构造器,Jackson 会报
InstantiationException;可用@JsonCreator标记静态工厂方法 - private 字段默认可读写:但若 JVM 启用了安全管理器(少见),或字段被 final 修饰且未初始化,反射赋值可能失败
- 性能开销真实存在:首次处理某个类时,反射查找字段、方法、构造器会有缓存构建成本;后续调用靠内部缓存提速,但依然比直接 new + set 慢 3–5 倍
- 混淆风险:ProGuard/R8 混淆时若未保留字段名和注解,会导致反序列化字段为空;需配置 keep 规则,如
-keepattributes Signature,Annotation
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











