最近在群里里面有哥们说在面试的时候,要求上机写一个简单的Json解析器,看到这个题目的时候,心里慌得一比,因为感觉有些力不从心,不知道从哪里下手,所以赶紧查了一下Gson源码,看看有什么启示没有。当然,这篇扯淡并不是介绍Gson源码,而是想自定义一个简单的Json解析器,来熟悉一下Java的反射知识和字符串操作知识。
先装个B,其实也没有我们想的辣么难啊,我们先来看看一般简单的Json字符串的格式:
"{'name':'tom', 'age':20 }"
我们该怎么下手呢?扯淡的话,就不多说了,我现在的想法就是逐个解析,看下图:
我对字符串逐个解析,去掉一些我们认为无用信息的字符,像啥{
,:
,'
等等字符,直接解析出我们想要的name
作为我们的key值,在提前知道要解析的JavaBean对象时,通过反射的方法知道name
将要对应的属性类型,比如说它是String类型,那么我再次对字符串逐个解析,将解析的String类型字符串通过反射方法赋值给JavaBean对象的属性对象,那么我们Json解析器就完成了。虽然说了这么多,也不知道说清楚没有,还是通过代码说明一下吧:
说先我们可以定义一个User类,源码如下;
public class User {
private String name;
private int age ;
//getter/setter方法省
}
通过反射方法,得到User类的属性值和属性类型:
Field[] fields = User.class.getDeclaredFields();
for(Field f : fields) {
System.out.println(f.getName() + "--->" + f.getType());
}
得到的结果为:
name--->class java.lang.String
age--->int
好了,我们现在知道了name
属性是String
类型的,age
属性是int
类型的,现在我们就准备解析Json字符串类了。
我们定义一个Reader对象,来获取相应的Json属性。【因为这是一道面试题,更多的是考察对Json认知的过程,所有下面的代码只是简单的介绍思路,问题肯定是有】:
public class Reader {
//去掉空格和一些非必须字符
public void nextWithNoSpace() {
//...
}
//获取下一段符合要求的String字符串
public String getNextString() {
//...
}
//获取下一段符合要求的int
public String getNextInt() {
//...
}
//数据是否解析完成
public boolean dataHasEnd() {
//...
}
//当然你还可以添加获取Double,char,byte,short,boolean等类型的数据
}
好了,思路到这,我们可以解析数据了,具体伪代码如下:
String jsonStr = "{'name':'tom', 'age':20 }" ;
//将jsonStr目标字符串进行解析
Reader reader = new Reader(jsonStr);
//循环解析字符串:
while(!reader.dataHasEnd()) {
//获取目标端的String字符串
String nextStr = reader.getNextString();
//通过反射获取User的实例方法:
//这也就是为啥Json解析时,所有的JavaBean都必须含有一个无参数构造器的原因
User user = User.class.getConstructor().newInstance()
//通过反射获取User的属性
Field[] fields = User.class.getDeclaredFields();
//遍历所有的属性,查找属性名与nextString对应的字段
//这也就是为啥JavaBean对应的字段与Json中对应的属性名一致了
for (Field field : fields) {
if(field.getName().equals(name)) {
//如果一致,查看这个属性是什么类型的:
//如果是Int类型的,那么可以告诉Reader,下一段解析你给我出个int类型的数据就行
if(field.getType() == Integer.class || type == int.class) {
//获取目标数据
int value = reader.getNextInt();
//通过反射将目标值注入:
if(!field.canAccess(object)) {
field.setAccessible(true);
field.set(user, params);
}
}
//String类型数据
else if(field.getType() == String.class) {
String value = reader.getNextString();
//同理直接注入
}
else {
//....其他类型数据
}
}
}
}
最终调用方式为:
private static final String JSON = "{'age':'25', 'name':'Steven' , 'data' : {'address':'sh'}}";
public static void main(String[] args) {
Object object = new MyGson().fromJson(JSON, User.class);
System.out.println(object);
}
调用结果为:
解析完成了,由于面试的时候比较紧张,但还是写出来了。其实你回家看看Json的原理,大致的原理和这个是差不多的,只不过人家考虑的东西非常多,像什么序列化/反序列化,泛型,各种注解,各种class嵌套和组合,不过大致的想法是和我们一致的,这里主要说一下思路,一开始拿到题目的时候还是懵逼的,不过慢慢分析就就不难了,还是平时需要多看源码啊,不然真的是知其然不知其所以然了啊。