解析器如何工作
阅读 aj-json 最简单的方式,是把它想成一条很小的流水线:一端放入字符串,另一端得到 Java 集合。
JSON 文本 → Lexer → token → FMS 状态机 → Map / List / 普通值
第一步:把文本切成有意义的小块
Lexer 逐个读取输入字符,把 {、}、[、]、,、: 等符号转换为 token;也会把相邻字符归成字符串、数字,以及 true、false、null。
以 {name: 7} 为例,重要的小块大致是:对象开始、name、冒号、7、对象结束。Lexer 还会记录行号和列号,以便后续报错时指出问题发生的位置。
第二步:检查这些小块的顺序
光有合法小块还不够。{ name 7 } 中每个小块都眼熟,但少了 :。FMS 是一个有限状态机:它在每一步都知道接下来允许出现什么。对象键之后应是 :;数组中的一个值之后应是 , 或 ]。
这就是项目里最简单的“编译原理”概念:先认出单词,再检查单词排列起来是否构成一句正确的话。
第三步:借助栈组装结果
状态机运行时,Operator 会维护几组栈:
- 对象栈:保存正在组装的 Map 和 List;
- 键栈:保存已经读到、正在等待值的对象键;
- 状态栈:在嵌套数组或对象结束后,回到外层的正确位置。
读到 { 时,它会新建 HashMap;读到 [ 时,会新建 ArrayList。嵌套值结束后,再放入外层正在组装的集合。因此对象和数组才能互相嵌套。
一个很有帮助的实验
从很短的输入开始,在 Lexer.next() 打断点,然后逐步执行 FMS.parse():
Object value = new FMS("{a:[1, true]}").parse();
观察每个 token 怎样改变状态,以及 Map、List 怎样逐渐长出来。接着删掉逗号或右括号,看看 JsonParseException 在哪里产生。这样理解比死记状态表更有效。
为什么不用于实际应用?
这份代码刻意保持小巧、便于教学。生产 JSON 处理需要严格遵循标准、可预测的数字处理、安全审查、性能优化、广泛测试、流式处理能力和长期兼容性。aj-json 的目标不包含这些。