Java反射不直接序列化,而是为Gson/Jackson等框架提供运行时解析类结构的能力:通过getDeclaredFields()、setAccessible()、get()/set()等操作动态读写字段,支撑未知类型(如Class<?> clazz)的序列化与反序列化全流程。

Java 中反射机制本身不直接做序列化与反序列化,而是为 Gson、Jackson 等框架提供“看懂类结构”的能力,从而让这些框架能处理未知类型对象(即编译期不确定、运行时才拿到 Class 的对象)。关键在于:反射是底层支撑,不是替代方案。
为什么需要反射来处理未知类型?
当你只有 Object obj 或一个 Class<?> clazz,却不知道它具体是 User、Order 还是 List<Product> 时:
- 编译器无法生成字段访问代码
- 没有硬编码的 setter/getter 可调用
- 字段名、类型、是否忽略、如何格式化——全靠运行时查
反射正是解决这个问题的唯一通用手段。
反射如何支撑未知类型的序列化
以 Jackson 为例,调用 mapper.writeValueAsString(obj) 时:
立即学习“Java免费学习笔记(深入)”;
- 通过
obj.getClass()获取Class对象 - 调用
clazz.getDeclaredFields()扫描所有字段(含 private) - 对每个字段:
-
field.setAccessible(true)打开私有访问 -
field.get(obj)读取值 - 根据字段类型(如
LocalDateTime)匹配内置或自定义 Serializer
-
- 字段名若被
@JsonProperty("user_name")修饰,就用注解值而非原始名
Gson 同理,只是用 FieldNamingPolicy 做字段名映射,底层仍是 getDeclaredFields() + get()。
反射如何支撑未知类型的反序列化
当执行 mapper.readValue(json, clazz)(注意第二个参数是 Class<T>):
- 框架用该
clazz创建实例:- 尝试无参构造器:
clazz.getDeclaredConstructor().newInstance() - 若有
@JsonCreator,则找对应构造器或静态工厂方法
- 尝试无参构造器:
- 解析 JSON 中的 key(如
"email"),用clazz.getDeclaredField("email")定位字段 - 若字段名不一致,通过
@JsonProperty("mail")注解找到真实字段 -
field.setAccessible(true)后调用field.set(instance, value)赋值 - 遇到嵌套类型(如字段是
Address),递归走同样流程——全程依赖反射导航类型树
✅ 关键点:你传入的
clazz是运行时才知道的,比如从字符串"com.example.User"通过Class.forName(className)加载而来。
手动用反射实现简易版(仅作理解,不推荐生产)
public static String serialize(Object obj) throws Exception {
Class<?> clazz = obj.getClass();
StringBuilder json = new StringBuilder("{");
Field[] fields = clazz.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
fields[i].setAccessible(true);
String name = fields[i].getName();
Object value = fields[i].get(obj);
json.append("\"").append(name).append("\":\"").append(value).append("\"");
if (i < fields.length - 1) json.append(",");
}
json.append("}");
return json.toString();
}⚠️ 注意:这没处理 null、嵌套对象、集合、类型转换、注解、循环引用等——正是 Gson/Jackson 用反射+大量策略封装的价值所在。
注意事项
-
setAccessible(true)在 JDK 12+ 受强封装限制,需添加 JVM 参数(如--illegal-access=permit)或改用MethodHandles(Jackson 已适配) - 泛型信息(如
List<String>)在运行时被擦除,需配合TypeReference或ParameterizedType+ 反射提取真实类型 -
transient字段默认跳过;static字段不参与序列化——反射扫描时会自然过滤(getDeclaredFields()返回所有字段,但框架逻辑会判断修饰符) -
serialVersionUID是 Java 原生序列化专用,JSON 框架完全不依赖它
不复杂但容易忽略


















