一道面試題之關於自定義Json解析器
阿新 • • 發佈:2018-11-10
最近在群裡裡面有哥們說在面試的時候,要求上機寫一個簡單的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巢狀和組合,不過大致的想法是和我們一致的,這裡主要說一下思路,一開始拿到題目的時候還是懵逼的,不過慢慢分析就就不難了,還是平時需要多看原始碼啊,不然真的是知其然不知其所以然了啊。