在咱們平常的編碼工做中,經常會制定或者遇到這樣的json結構java
{
"resultcode": "200",
"reason": "成功的返回",
"result": {
"area": "浙江省溫州市平陽縣",
"sex": "男",
"birthday": "1989年03月08日"
}
}
複製代碼
對於該接口的提供者,最外層的resultcode
reason
和result
這三個元素都是有的。所以咱們能夠定義一個這樣的Response
類json
public class Response<T> {
private String resultcode;
private String reason;
private T result;
}
複製代碼
使用泛型來決定result最終向裏面填充什麼東西。固然,這裏所填充的是一個對象,姑且咱們也能夠將它定義爲User
類bash
public class User {
private String area;
private String sex;
private String birthday;
}
複製代碼
這樣,咱們的數據就能夠按照示例json的約定規則,返回給調用者了。 而做爲調用方,也就是接收這條數據的機器,咱們則須要定義以下的類ResopnseUser
函數
public class ResopnseUser {
private String resultcode;
private String reason;
private User result;
}
public class User {
private String area;
private String sex;
private String birthday;
}
複製代碼
而後咱們可使用fastJson來進行愉快的解析了ui
String testJson = "{\"resultcode\":\"200\",\"reason\":\"成功的返回\",\"result\":{\"area\":\"浙江省溫州市平陽縣\",\"sex\":\"男\",\"birthday\":\"1989年03月08日\"}}";
ResponseUser response1 = JSONObject.parseObject(testJson,ResponseUser.class);
複製代碼
能夠看到,也確實獲得了咱們想要的結果 編碼
可是,這有個不太嚴重的後果。我每跟提供者對接一個接口,就得生成一個與之對應的類。長此以往,這些專用的類會變得愈來愈多,嵌套也會愈來愈深。既然提供者能夠抽象出一個Response
類,那麼我是否也能夠向提供者那樣處理?spa
String testJson = "{\"resultcode\":\"200\",\"reason\":\"成功的返回\",\"result\":{\"area\":\"浙江省溫州市平陽縣\",\"sex\":\"男\",\"birthday\":\"1989年03月08日\"}}";
Response<User> response = JSONObject.parseObject(testJson,Response.class);
複製代碼
很遺憾,咱們獲得的結果並不是所指望的,只有最外層的數據解析成功了,內層的result
還是JSONObject
. debug
幸運的事,在這萬千工程師中並不是只有想到了這種處理辦法,而且已經有人解決這類問題了! 經過各類搜索下來,咱們發現了fastJson提供了TypeReference
這個類,能夠解決咱們的問題。code
String testJson = "{\"resultcode\":\"200\",\"reason\":\"成功的返回\",\"result\":{\"area\":\"浙江省溫州市平陽縣\",\"sex\":\"男\",\"birthday\":\"1989年03月08日\"}}";
Response<User> response = JSONObject.parseObject(testJson,new TypeReference<Response<User>>(){});
複製代碼
等等,就沒有發現什麼問題嗎?泛型在編譯時會執行類型擦除啊!這也就是咱們第一次直接使用Response<User> response = JSONObject.parseObject(testJson,Response.class);
時無效的緣由。 那麼,即便咱們這麼寫了new TypeReference<Response<User>>(){}
不也同樣會被擦除掉嗎?運行時它是如何獲取到咱們所定義的實際類型的? 經過查看TypeReference
的源碼,幸運的是該源碼十分的簡單並且代碼量少。首先進入的就是它的構造函數protected TypeReference()
,經過debug咱們發現,在代碼執行到第二行時,就已經得到了咱們所寫的泛型.cdn
Type superClass = getClass().getGenericSuperclass();
Type type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
複製代碼
這段代碼很簡單,獲取到它的父類getGenericSuperclass()
就獲取到了實際的類型.繼續跟進代碼,咱們能夠發現它調用了一個native方法private native String getGenericSignature0();
獲取到了該類和父類的一些信息ClassRepository
和Type
。 此時,回過頭來咱們再看new TypeReference<Response<User>>(){}
實際上是建立了一個TypeReference
的匿名內部類,經過該類的getGenericSuperclass()
,獲取到了實際的類型信息。
讓咱們如今回顧一下咱們的所得,注要有2點:
getGenericSuperclass()
就獲取到了實際的類型。 等等,這兩點是互相矛盾的啊。1說沒有,2又說還能找到,究竟是怎麼回事呢?經過查看編譯後的字節碼文件,咱們找到了答案。
Response<User> response = JSONObject.parseObject(testJson,new TypeReference<Response<User>>(){});
的方法的class文件反編譯後的信息。咱們能夠看到 它多了一個LocalvariableTypeTable
,裏面的Signature
正好存儲了實際的類型信息。**也就是說類型並未徹底擦除,咱們依然能夠經過反射的方式拿到參數的類型。**所謂的擦除,只是把方法 code
屬性的字節碼進行擦除。 另外,咱們還看到了InnerClasses
列表中,有一個內部類,叫Main$1,也就是咱們的這個new TypeReference<Response<User>>(){}
JSONObject.parseObject(testJson,new TypeReference<Response<User>>(){});
的方式,解決json中嵌套泛型的問題。方便、快捷、直觀getClass().getGenericSuperclass();
獲取到真實類型。驗證代碼// 這類建立了一個HashMap的匿名子類
HashMap<String,Integer> subIntMap = new HashMap<String,Integer>(){};
System.out.println(subIntMap.getClass().getSuperclass());
Type subClassType = subIntMap.getClass().getGenericSuperclass();
if(subClassType instanceof ParameterizedType){
ParameterizedType p = (ParameterizedType) subClassType;
for (Type t : p.getActualTypeArguments()){
System.out.println(t);
}
}
複製代碼
輸出結果
class java.util.HashMap
class java.lang.String
class java.lang.Integer
複製代碼
ResponseUser response = new ResponseUser();
Field field = response.getClass().getField("result");
System.out.println("result Type is "+ field.getType());
System.out.println("result GenericType is "+ field.getGenericType());
public class ResponseUser {
private String resultcode;
private String reason;
public List<User> result;
}
複製代碼
輸出結果
result Type is interface java.util.List
result GenericType is java.util.List<com.jd.jr.alpha.cpa.fastJson.User>
複製代碼