💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] ## 手写Json解析(仿Gson) ### Reader ~~~ public class Reader { private char[] buffer; private int pos; public Reader(String json) { buffer = json.toCharArray(); pos = 0; } ublic char next() throws BufferException{ if (pos < buffer.length){ return buffer[pos]; } throw new BufferException("no next"); } public void skipNext() { pos ++; } public void moveToLast() { pos --; } public String nextName() { //读取下一个名称 知道遇到下一个 '"' return nextString(); } //读取下一个value 根据类型的区别 分为 nextBoolean() nextDouble() nextFloat()... public String nextNumString() { nextNonWhitespace(); StringBuilder stringBuilder = new StringBuilder(); char c; while (pos < buffer.length){ c = buffer[pos ++]; if (c == '"' && stringBuilder.length() <= 0){ continue; }else if (c > '0' && c < '9' || c == '.' || c == '-'){ stringBuilder.append(c); }else { pos --; break; } } return stringBuilder.toString(); } } ~~~ ### Parser ~~~ public interface Parser { Object parse(Reader reader); } ~~~ 解析器安装类型可以分为 ObjectParser , PrimitiveParser(基本类型) , ArrayParser , NullParser 下面以ObjectParser为例 ### ObjectParser ~~~ public class ObjectParser implements Parser { private static final int START_TAG = -1; private static final int OBJECT = 0; private static final int NAME = 1; private static final int VALUE = 2; private Stack<Integer> stack;//核心操作栈 private Stack<String> nameStack;//名称张 private Class<?> raw; private Map<String, Field> map; // <fieldName, typeName> private Map<String, Object> map; // <fieldName, typeName> public ObjectParser(Class<?> raw) { this.raw = raw; map = new HashMap<>(); stack = new Stack<>(); nameStack = new Stack<>(); } public Object parse(Reader reader) { //一次性class对象解析,存入map Field[] fields = raw.getDeclaredFields(); for (Field f : fields){ String name = f.getName(); map.put(name, f); } Object instance; try { instance = raw.newInstance(); } catch (Exception e) { return null; } stack.push(START_TAG); while (reader.hasNext() && !stack.empty()){ //为了第一次能往下执行初始化 if (stack.peek() == START_TAG){ stack.pop(); } char c; try { c = reader.next(); } catch (Reader.BufferException e) { e.printStackTrace(); break ; } reader.skipNext(); Logger.d("c is " + c); switch (c){ case '{': if (stack != null && !stack.isEmpty() && stack.peek() == VALUE){ //如果是value reader.moveToLast(); setValue(reader, instance); }else { //否则就是key stack.push(OBJECT); stack.push(NAME); } continue; case '"': if (stack.peek() == NAME){ //如果是name String name = reader.nextName(); nameStack.push(name); stack.pop(); }else if (stack.peek() == VALUE){ //如果是value setValue(reader, instance); } break; case ',': stack.push(NAME); break; case ':': stack.push(VALUE); break; case '}': if (stack.peek() == OBJECT){ stack.pop(); } break; case ' ': case '\n': break; default: reader.moveToLast(); setNameAndValue(reader, instance); break; } } return instance; } private void setValue(Reader reader, Object instance) { //根据类型的不同 初始化不同的 使用不同Parser //通过反射Field的值调用不同的值Par ~~~ 核心思想: 维护一个操作指令栈 ## Gson //todo 研究gson的源码 ## FastJson为什么快 ### 序列化 1. 缓存各种序列化处理类,包括各种基本对象、集合对象、第三方对象、自定义对象,方便序列化处理类的快速查找、避免JavaBeanSerializer的反复创建 2. 使用ThreadLocal来存储序列化过程中不断append的字符串,减少内存分配和gc,从而提高性能。 3. 用类StringBuilder方式进行字符串操作,配合ThreadLocal实现线程安全的StringBuilder。(StringBuilder线程不安全但效率改哦) 4. 缺省启用sort field输出,为deserialize优化做准备。 5. 使用asm高效反射 就是使用不同的反射机制 ### 反序列化 1. IdentityHashMap缓存各种反序列化处理类,包括基本对象、集合对象、第三方对象、自定义对象,方便反序列化类的快速查找、避免JavaBeanDeserializer的反复创建。代码与序列化的处理类缓存相似 2. 读取token基于预测。在反序列化一个json字符串时,下一个字符一般情况下是可以预估的。比如字符}之后最有可能出现的是“,”、“\]”、“}”或者结束符,有计划、有预测地判断token将能提升不少性能。(其实就是json字符串是有规律的, 后面结束符是可以提前只是,只要做好匹配就好) 3. 快速匹配。在Fastjson反序列化过程中,有一个非常有用的效率改进方法是有序json的快速匹配。所谓有序json就是json字符串中的key是按照字符排序好了的。上面已经说过,Fastjson的序列化默认是按照key的顺序进行的,因此做反序列化时候,Fastjson采用一种优化算法,就是假设key/value的内容是有序的,读取的时候只需要做key的匹配,而不需要把key从输入中读取出来。( key的顺序与 field的顺序一直值时,就可以不要匹配查找,直接比较赋值) 4. 使用asm高效反射(同上序列化的asm反射) 5. symbolTable算法缓存关键字,避免创建新的字符串对象。 6. ## 参考资料 [JsonParser](https://github.com/5A59/JsonParser)