一道面试题之关于自定义Json解析器

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013762572/article/details/80865921

最近在群里里面有哥们说在面试的时候,要求上机写一个简单的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嵌套和组合,不过大致的想法是和我们一致的,这里主要说一下思路,一开始拿到题目的时候还是懵逼的,不过慢慢分析就就不难了,还是平时需要多看源码啊,不然真的是知其然不知其所以然了啊。

猜你喜欢

转载自blog.csdn.net/u013762572/article/details/80865921