java反射自定义序列化核心是运行时递归探查字段与引用关系,需处理字段可访问性、循环引用(用identityhashmap检测)、继承链字段收集、类型适配(string加引号、数字不加引号等)、缩进格式化及安全控制(白名单、敏感字段过滤、深度限制)。

Java 反射机制在自定义序列化工具中提取对象图结构,核心是绕过编译期类型约束,运行时递归探查对象的字段、类型和引用关系。它不依赖外部库,但需手动处理字段可访问性、循环引用、嵌套边界和类型适配等关键问题。
获取全部可读字段(含继承链)
要完整还原对象图,不能只看当前类的字段。需向上遍历继承链,收集所有非 static、非 transient 的可读字段:
- 调用
clazz.getDeclaredFields()获取本类声明字段,对每个字段执行setAccessible(true)突破 private 限制 - 用
clazz.getSuperclass()向上迭代,重复获取父类字段;遇到null(即 Object 类)停止 - 跳过
static和transient字段——它们通常不参与业务序列化 - 忽略方法、构造器、内部类声明等无关成员,
getDeclaredFields()本身已过滤这些
安全递归遍历与循环引用拦截
对象图天然可能成环(如父子双向引用),直接递归会栈溢出。必须引入引用身份快照机制:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 使用
IdentityHashMap<object string></object>记录已访问对象的原始引用(不是 equals 比较,而是内存地址级) - 每次进入新对象前,先查 map:若已存在,返回
{"$ref": "obj_12345"}占位符,不继续展开 - 首次访问时,分配唯一 ID(例如
"obj_" + System.identityHashCode(obj)),并存入 map - 对
List、Map、数组等容器类型,同样做引用检测,避免重复序列化同一集合实例
按类型生成 JSON 片段并格式化
字段值类型决定输出语法,拼接过程需兼顾可读性与合法性:
-
String→ 加双引号,内部特殊字符(如换行、引号)需转义 - 数字(
int/long/double等)→ 直接拼接,不加引号;注意NaN、Infinity需转为null或抛异常 -
Boolean→ 输出true或false -
null→ 输出字面量null - 数组 /
Collection→ 用[]包裹,元素递归序列化 -
Map或普通 Bean → 用{}包裹,key 强制转为String(如map.keySet().stream().map(Object::toString)) - 用
StringBuilder累加,每层嵌套增加 2 或 4 空格缩进,避免字符串频繁创建
控制输出安全性与粒度
生产环境不能无条件展开所有字段,需内置防护策略:
- 支持字段白名单:仅序列化标注
@JsonInclude或出现在配置列表中的字段 - 自动过滤敏感字段:如含
password、token、secret等关键词的字段名,一律跳过 - 空值处理:提供开关,控制是否输出
"field": null还是彻底省略该键值对 - 深度限制:递归超过指定层数(如 8 层)时终止,并插入
{"$truncated": true}提示 - 特殊类型兜底:
Date转 ISO8601;byte[]默认 Base64 编码;枚举取name()
不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










