【原標題:bigdecimal類解決Java精度問題 Java 工程師成神之路】前言之前一段時間,準備把糗百的項目中json解析的模塊中的原生Json解析換成gson解析,工作比較繁雜,坑多,因此為了防止出錯,我還對Gson做了一個源碼分析。這一篇就是Gson源碼分析的總結(jié),同時對Gson內(nèi)部運用的設(shè)計模式也進行了總結(jié),相信了解了它的源碼和運行機制,對于使用Gson的使用會更有幫助。
Gson簡介
Gson,就是幫助我們完成序列化和反序列化的工作的一個庫。
日常用法
UserInfouserInfo=getUserInfo();
Gsongson=newGson();
StringjsonStr=gson.toJson(userInfo);//序列化
UserInfouser=gson.fromJson(jsonStr,UserInfo.class);//反序列化
實際上我們用的最多的是Gson的反序列化,主要在解析服務器返回的json串。因此,后面的文章也會以Gson中的反序列化的過程為主來分析代碼。
在分析之前,我們先做個簡單的猜想,要如何實現(xiàn)反序列化的流程的,Gson大體會做一下這三件事:
反射創(chuàng)建該類型的對象
把json中對應的值賦給對象對應的屬性
返回該對象。
事實上,Gson想要把json數(shù)據(jù)反序列化基本都逃不掉這三個步驟,但是這三個步驟就像小品里分三步把大象裝進冰箱一樣。我們知道最復雜的一步就是把大象裝進去,畢竟,開冰箱門或者關(guān)冰箱門大家都會的嘛。在Gson中,復雜的就是怎樣把json中對應數(shù)據(jù)放入對應的屬性中。而這個問題的答案就是Gson的TypeAdapter。
Gson核心:TypeAdapterTypeAdapter是Gson的核心,它的意思是類型適配器,而說到適配器,大家都會想到適配器模式,沒錯,這個TypeAdapter的設(shè)計這確實是一個適配器模式,因為Json數(shù)據(jù)接口和Type的接口兩者是無法兼容,因此TypeAdapter就是來實現(xiàn)兼容,把json數(shù)據(jù)讀到Type中,把Type中的數(shù)據(jù)寫入到Json里。
publicabstractclassTypeAdapter
//JsonWriter代表Json數(shù)據(jù),T則是對應的Type的對象
publicabstractvoidwrite(JsonWriterout,Tvalue)throwsIOException;
//JsonWriter代表Json數(shù)據(jù),T則是對應的Type的對象
publicabstractTread(JsonReaderin)throwsIOException;
...
...
...
}
簡單而言,TypeAdapter的作用就是針對Type進行適配,保證把json數(shù)據(jù)讀到Type中,或者把Type中的數(shù)據(jù)寫入到Json里
Type和TypeAdapter的對應關(guān)系Gson會為每一種類型創(chuàng)建一個TypeAdapter,同樣的,每一個Type都對應唯一一個TypeAdapter
而所有Type(類型),在Gson中又可以分為基本類型和復合類型(非基本類型)
基本類型(Integer,String,Uri,Url,Calendar…):這里的基本類型不僅包括Java的基本數(shù)據(jù)類型,還有很多其他的數(shù)據(jù)類型
復合類型(非基本類型):即除了基本類型之外的類型,往往是我們自定義的一些業(yè)務相關(guān)的JavaBean,比如User,Article…..等等。
這里的基本類型和復合類型(非基本類型)是筆者定義的詞匯,因為這樣定義對于讀者理解Gson源碼和運行機制更有幫助。
如上圖,每一種基本類型都會創(chuàng)建一個TypeAdapter來適配它們,而所有的復合類型(即我們自己定義的各種JavaBean)都會由ReflectiveTypeAdapter來完成適配
TypeAdapter和Gson運行機制既然講到了每種Type都有對應的TypeAdapter,那么為什么說TypeAdapter是Gson的核心呢?我們可以看看Gson到底是如何實現(xiàn)Json解析的呢,下圖是Gson完成json解析的抽象簡化的流程圖:
如上圖,如果是基本類型,那么對應的TypeAdapter就可以直接讀寫Json串,如果是復合類型,ReflectiveTypeAdapter會反射創(chuàng)建該類型的對象,并逐個分析其內(nèi)部的屬性的類型,然后重復上述工作。直至所有的屬性都是Gson認定的基本類型并完成讀寫工作。
TypeAdapter源碼分析當類型是復合類型的時候,Gson會創(chuàng)建ReflectiveTypeAdapter,我們可以看看這個Adapter的源碼:
//創(chuàng)建ReflectiveTypeAdapter
newAdapter
...
...
/**
*ReflectiveTypeAdapter是ReflectiveTypeAdapterFactory的內(nèi)部類,其實際的類名就是Adapter
*本文只是為了區(qū)別其他的TypeAdapter而叫它ReflectiveTypeAdapter
**/
publicstaticfinalclassAdapter
//該復合類型的構(gòu)造器,用于反射創(chuàng)建對象
privatefinalObjectConstructor
//該類型內(nèi)部的所有的Filed屬性,都通過map存儲起來
privatefinalMap
Adapter(ObjectConstructor
this.constructor=constructor;
this.boundFields=boundFields;
}
//JsonReader是Gson封裝的對Json相關(guān)的操作類,可以依次讀取json數(shù)據(jù)
//類似的可以參考Android封裝的對XML數(shù)據(jù)解析的操作類XmlPullParser
@OverridepublicTread(JsonReaderin)throwsIOException{
if(in.peek()==JsonToken.NULL){
in.nextNull();
returnnull;
}
Tinstance=constructor.construct();
try{
in.beginObject();//從“{”開始讀取
while(in.hasNext()){
Stringname=in.nextName();//開始逐個讀取json串中的key
BoundFieldfield=boundFields.get(name);//通過key尋找對應的屬性
if(field==null||!field.deserialized){
in.skipValue();
}else{
field.read(in,instance);//將json串的讀取委托給了各個屬性
}
}
}catch(IllegalStateExceptione){
thrownewJsonSyntaxException(e);
}catch(IllegalAccessExceptione){
thrownewAssertionError(e);
}
in.endObject();//到對應的“}”結(jié)束
returninstance;
}
...
...
}
Gson內(nèi)部并沒有ReflectiveTypeAdapter這個類,它其實際上是ReflectiveTypeAdapterFactory類一個名叫Adapter的內(nèi)部類,叫它ReflectiveTypeAdapter是為了表意明確。
我們看到,ReflectiveTypeAdapter內(nèi)部會首先創(chuàng)建該類型的對象,然后遍歷該對象內(nèi)部的所有屬性,接著把json傳的讀去委托給了各個屬性。
被委托的BoundField內(nèi)部又是如何做的呢?BoundField這個類,是對Filed相關(guān)操作的封裝,我們來看看BoundField是如何創(chuàng)建的,以及內(nèi)部的工作原理。
//創(chuàng)建ReflectiveTypeAdaptergetBoundFields獲取該類型所有的屬性
newAdapter
...
...
privateMap
//創(chuàng)建一個Map結(jié)構(gòu),存放所有的BoundField
Map
if(raw.isInterface()){
returnresult;
}
TypedeclaredType=type.getType();
while(raw!=Object.class){//如果類型是Object則結(jié)束循環(huán)
Field[]fields=raw.getDeclaredFields();//獲取該類型的所有的內(nèi)部屬性
for(Fieldfield:fields){
booleanserialize=excludeField(field,true);
booleandeserialize=excludeField(field,false);
if(!serialize&&!deserialize){
continue;
}
accessor.makeAccessible(field);
TypefieldType=$Gson$Types.resolve(type.getType(),raw,field.getGenericType());
List
BoundFieldprevious=null;
for(inti=0,size=fieldNames.size();i Stringname=fieldNames.get(i); //多個解析名,第一作為默認的序列化名稱 if(i!=0)serialize=false;//onlyserializethedefaultname //創(chuàng)建BoundField BoundFieldboundField=createBoundField(context,field,name, TypeToken.get(fieldType),serialize,deserialize); //將BoundField放入Map中,獲取被替換掉的value(如果有的話) BoundFieldreplaced=result.put(name,boundField); //做好記錄 if(previous==null)previous=replaced; } if(previous!=null){ //如果previous!=null證明出現(xiàn)了兩個相同的Filedname,直接拋出錯誤 //注:Gson不允許定義兩個相同的名稱的屬性(父類和子類之間可能出現(xiàn)) thrownewIllegalArgumentException(declaredType +"declaresmultipleJSONfieldsnamed"+previous.name); } } type=TypeToken.get($Gson$Types.resolve(type.getType(),raw,raw.getGenericSuperclass())); raw=type.getRawType();//獲取父類類型,最終會索引到Object.因為Object是所有對象的父類 } returnresult; } 上面這段代碼的主要工作就是,找到該類型內(nèi)部的所有屬性,并嘗試逐一封裝成BoundField。 //根據(jù)每個Filed創(chuàng)建BoundField(封裝Filed讀寫操作) privateReflectiveTypeAdapterFactory.BoundFieldcreateBoundField( finalGsoncontext,finalFieldfield,finalStringname, finalTypeTokenfieldType,booleanserialize,booleandeserialize){ //是否是原始數(shù)據(jù)類型(int,boolean,float...) finalbooleanisPrimitive=Primitives.isPrimitive(fieldType.getRawType()); ... ... if(mapped==null){ //Gson嘗試獲取該類型的TypeAdapter,這個方法我們后面也會繼續(xù)提到。 mapped=context.getAdapter(fieldType); } //final變量,便于內(nèi)部類使用 finalTypeAdaptertypeAdapter=mapped; returnnewReflectiveTypeAdapterFactory.BoundField(name,serialize,deserialize){ ... ... //ReflectiveTypeAdapter委托的Json讀操作會調(diào)用到這里 @Overridevoidread(JsonReaderreader,Objectvalue) throwsIOException,IllegalAccessException{ //通過該屬性的類型對應的TypeAdapter嘗試讀取json串 //如果是基礎(chǔ)類型,則直接讀取, //如果是復合類型則遞歸之前的流程 ObjectfieldValue=typeAdapter.read(reader); if(fieldValue!=null||!isPrimitive){ field.set(value,fieldValue);//更新filed值 } } @OverridepublicbooleanwriteField(Objectvalue)throwsIOException,IllegalAccessException{ if(!serialized)returnfalse; ObjectfieldValue=field.get(value); returnfieldValue!=value;//avoidrecursionforexampleforThrowable.cause } }; } 假設(shè)該復合類型中所有的屬性的類型是String,則屬性所對應的TypeAdapter以及其讀寫方式如下: publicstaticfinalTypeAdapter @Override publicStringread(JsonReaderin)throwsIOException{ JsonTokenpeek=in.peek();//獲取下一個jsontoken而不消耗它 if(peek==JsonToken.NULL){ in.nextNull(); returnnull; } /*coercebooleanstostringsforbackwardscompatibility*/ if(peek==JsonToken.BOOLEAN){ returnBoolean.toString(in.nextBoolean());//如果時布爾值,則轉(zhuǎn)化為String } returnin.nextString();//從json串中獲取這個String類型的value并消耗它 } @Override publicvoidwrite(JsonWriterout,Stringvalue)throwsIOException{ out.value(value);//不做任何處理直接寫入Json串 } } 到這里,關(guān)于Gson的TypeAdapter的原理也就講得差不多了,回顧一下,因為Type有兩類,對應的TypeAdapter也有兩類,一類是ReflectiveTypeAdapter,針對復合類型,它的作用是把復合類型拆解成基本類型,另一類是針對基本類型的TypeAdapter,實現(xiàn)對應基本類型的Json串讀寫工作。而Gson本質(zhì)上就是按照這兩類TypeAdapter來完成Json解析的。 可以說,到這里,我們現(xiàn)在對Gson的基本工作流程有了一個基本的認識。 再一次分析Gson的執(zhí)行邏輯事實上,文章到這里結(jié)合上面的源碼剖析和簡化流程圖,我們已經(jīng)可以比較比較真實的分析出Gson的執(zhí)行邏輯了。 Gson反序列化的日常用法: UserInfouserInfo=getUserInfo(); Gsongson=newGson(); StringjsonStr=getJsonData(); UserInfouser=gson.fromJson(jsonStr,UserInfo.class);//反序列化 gson.fromJson(jsonStr,UserInfo.class)方法內(nèi)部真實的代碼執(zhí)行流程大致如下: 對jsonStr,UserInfo.class這兩個數(shù)據(jù)進行封裝 通過UserInfo.class這個Type來獲取它對應的TypeAdapter 拿到對應的TypeAdapter(ReflectiveTypeAdapterFactor),并執(zhí)行讀取json的操作 返回UserInfo這個類型的對象。 我們描述的這個流程和Gson代碼真實的執(zhí)行流程已經(jīng)沒太大的區(qū)別了。 TypeAdapter的創(chuàng)建與工廠模式Gson中除了適配器模式之外最重要的設(shè)計模式,可能就是工廠模式吧。因為Gson中眾多的TypeAdapter都是通過工廠模式統(tǒng)一創(chuàng)建的: publicinterfaceTypeAdapterFactory{ //創(chuàng)建TypeAdapter的接口 } 我們可以看看ReflectiveTypeAdapterFactory的實現(xiàn) //ReflectiveTypeAdapterFactory的實現(xiàn) publicfinalclassReflectiveTypeAdapterFactoryimplementsTypeAdapterFactory{ @Overridepublic Classraw=type.getRawType(); //只要是Object的子類,就能匹配上 if(!Object.class.isAssignableFrom(raw)){ //it'saprimitive! returnnull; } ObjectConstructor returnnewAdapter } } Gson在其構(gòu)造方法中,就提前把所有的TypeAdapterFactory放在緩存列表中。 Gson(finalExcluderexcluder,finalFieldNamingStrategyfieldNamingStrategy, finalMap booleancomplexMapKeySerialization,booleangenerateNonExecutableGson,booleanhtmlSafe, booleanprettyPrinting,booleanlenient,booleanserializeSpecialFloatingPointValues, LongSerializationPolicylongSerializationPolicy,StringdatePattern,intdateStyle, inttimeStyle,List List List ... ... ... List //built-intypeadaptersthatcannotbeoverridden factories.add(TypeAdapters.JSON_ELEMENT_FACTORY); factories.add(ObjectTypeAdapter.FACTORY); //theexcludermustprecedealladaptersthathandleuser-definedtypes factories.add(excluder); //userstypeadapters factories.addAll(factoriesToBeAdded); //typeadaptersforbasicplatformtypes factories.add(TypeAdapters.STRING_FACTORY); factories.add(TypeAdapters.INTEGER_FACTORY); factories.add(TypeAdapters.BOOLEAN_FACTORY); factories.add(TypeAdapters.BYTE_FACTORY); factories.add(TypeAdapters.SHORT_FACTORY); TypeAdapter factories.add(TypeAdapters.newFactory(long.class,Long.class,longAdapter)); factories.add(TypeAdapters.newFactory(double.class,Double.class, doubleAdapter(serializeSpecialFloatingPointValues))); factories.add(TypeAdapters.newFactory(float.class,Float.class, floatAdapter(serializeSpecialFloatingPointValues))); factories.add(TypeAdapters.NUMBER_FACTORY); factories.add(TypeAdapters.ATOMIC_INTEGER_FACTORY); factories.add(TypeAdapters.ATOMIC_BOOLEAN_FACTORY); factories.add(TypeAdapters.newFactory(AtomicLong.class,atomicLongAdapter(longAdapter))); factories.add(TypeAdapters.newFactory(AtomicLongArray.class,atomicLongArrayAdapter(longAdapter))); factories.add(TypeAdapters.ATOMIC_INTEGER_ARRAY_FACTORY); factories.add(TypeAdapters.CHARACTER_FACTORY); factories.add(TypeAdapters.STRING_BUILDER_FACTORY); factories.add(TypeAdapters.STRING_BUFFER_FACTORY); factories.add(TypeAdapters.newFactory(BigDecimal.class,TypeAdapters.BIG_DECIMAL)); factories.add(TypeAdapters.newFactory(BigInteger.class,TypeAdapters.BIG_INTEGER)); factories.add(TypeAdapters.URL_FACTORY); factories.add(TypeAdapters.URI_FACTORY); factories.add(TypeAdapters.UUID_FACTORY); factories.add(TypeAdapters.CURRENCY_FACTORY); factories.add(TypeAdapters.LOCALE_FACTORY); factories.add(TypeAdapters.INET_ADDRESS_FACTORY); factories.add(TypeAdapters.BIT_SET_FACTORY); factories.add(DateTypeAdapter.FACTORY); factories.add(TypeAdapters.CALENDAR_FACTORY); factories.add(TimeTypeAdapter.FACTORY); factories.add(SqlDateTypeAdapter.FACTORY); factories.add(TypeAdapters.TIMESTAMP_FACTORY); factories.add(ArrayTypeAdapter.FACTORY); factories.add(TypeAdapters.CLASS_FACTORY); //typeadaptersforcompositeanduser-definedtypes factories.add(newCollectionTypeAdapterFactory(constructorConstructor)); factories.add(newMapTypeAdapterFactory(constructorConstructor,complexMapKeySerialization)); this.jsonAdapterFactory=newJsonAdapterAnnotationTypeAdapterFactory(constructorConstructor); factories.add(jsonAdapterFactory); factories.add(TypeAdapters.ENUM_FACTORY); //注意,ReflectiveTypeAdapterFactor是要最后添加的 factories.add(newReflectiveTypeAdapterFactory( constructorConstructor,fieldNamingStrategy,excluder,jsonAdapterFactory)); this.factories=Collections.unmodifiableList(factories); } 這里我們能夠看到,ReflectiveTypeAdapterFactor最后被添加進去的,因為這里的添加順序是有講究的。我們看看getAdapter(type)方法就能知道。 getAdapter(type)這個方法就是gson通過type尋找到對應的TypeAdapter,這是Gson中非常重要的一個方法。 //通過Type獲取TypeAdapter public try{ //遍歷緩存中所有的TypeAdapterFactory, for(TypeAdapterFactoryfactory:factories){ //如果類型匹配,則create()將會返回一個TypeAdapter,否則為nulll TypeAdapter if(candidate!=null){ //candidate不為null,證明找到類型匹配的TypeAdapter. returncandidate; } } thrownewIllegalArgumentException("GSON("+GsonBuildConfig.VERSION+")cannothandle"+type); } } ReflectiveTypeAdapterFactory之所以在緩存列表的最后一個,就是因為它能匹配幾乎任何類型,因此,我們?yōu)橐粋€類型遍歷時,只能先判斷它是不是基本類型,如果都不成功,最后再使用ReflectiveTypeAdapterFactor進行判斷。 這就是Gson中用到的工廠模式。 關(guān)于代碼的難點我們重新回到getAdapter(type)這個方法,這個方法里面有一些比較難理解的代碼 //通過Type獲取TypeAdapter public //typeTokenCache是Gson的一個Map類型的緩存結(jié)構(gòu) //0,首先嘗試從緩存中獲取是否有對應的TypeAdapter TypeAdaptercached=typeTokenCache.get(type==null?NULL_KEY_SURROGATE:type); if(cached!=null){ return(TypeAdapter } //1,alls是Gson內(nèi)部的ThreadLocal變量,用于保存一個Map對象 //map對象也緩存了一種FutureTypeAdapter Map booleanrequiresThreadLocalCleanup=false; if(threadCalls==null){ threadCalls=newHashMap calls.set(threadCalls); requiresThreadLocalCleanup=true; } //2,如果從ThreadLocal內(nèi)部的Map中找到緩存,則直接返回 //thekeyandvaluetypeparametersalwaysagree FutureTypeAdapter if(ongoingCall!=null){ returnongoingCall; } try{ 創(chuàng)建一個FutureTypeAdapter FutureTypeAdapter //緩存 threadCalls.put(type,call); for(TypeAdapterFactoryfactory:factories){ //遍歷所有的TypeAdapterFactory TypeAdapter if(candidate!=null){ //3,設(shè)置委托的TypeAdapter call.setDelegate(candidate); //緩存到Gson內(nèi)部的Map中, typeTokenCache.put(type,candidate); returncandidate; } } //如果遍歷都沒有找到對應的TypeAdapter,直接拋出異常 thrownewIllegalArgumentException("GSON("+GsonBuildConfig.VERSION+")cannothandle"+type); }finally{ //4,移除threadCalls內(nèi)部緩存的FutureTypeAdapter threadCalls.remove(type); if(requiresThreadLocalCleanup){ //ThreadLocal移除該線程環(huán)境中的Map calls.remove(); } } } 上述代碼比較難以理解的地方我標注了序號,用于后面解釋代碼 方法里出現(xiàn)了FutureTypeAdapter這個TypeAdapter,似乎很奇怪,因為它沒有FutureTypeAdapterFactory這個工廠類,我們先來看看 FutureTypeAdapter的內(nèi)部構(gòu)造 staticclassFutureTypeAdapter privateTypeAdapter publicvoidsetDelegate(TypeAdapter if(delegate!=null){ thrownewAssertionError(); } delegate=typeAdapter; } @OverridepublicTread(JsonReaderin)throwsIOException{ if(delegate==null){ thrownewIllegalStateException(); } returndelegate.read(in); } @Overridepublicvoidwrite(JsonWriterout,Tvalue)throwsIOException{ if(delegate==null){ thrownewIllegalStateException(); } delegate.write(out,value); } } 這是一個明顯的委派模式(也可稱為代理模式)的包裝類。我們都知道委托模式的功能是:隱藏代碼具體實現(xiàn),通過組合的方式同樣的功能,避開繼承帶來的問題。但是在這里使用委派模式似乎并不是基于這些考慮。而是為了避免陷入無限遞歸導致對棧溢出的崩潰。 為什么這么說呢?我們來舉個例子: //定義一個帖子的實體 publicclassArticle{ //表示帖子中鏈接到其他的帖子 publicArticlelinkedArticle; ..... ..... ..... } Article類型中有一個linkedArticle屬性,它的類型還是Article,根據(jù)我們之前總結(jié)的簡化流程圖: 你會發(fā)現(xiàn)這里有一個死循環(huán),或者說無法終結(jié)的遞歸。為了避免這個問題,所以先創(chuàng)建一個代理類,等到遞歸遇到同樣的類型時直接復用返回,避免無限遞歸。也就是注釋2那段代碼的用意,在注釋3處,再將創(chuàng)建成功的TypeAdapter設(shè)置到代理類中。就基本解決這個問題了。 當然說基本解決,是因為還要考慮多線程的環(huán)境,所以就出現(xiàn)了ThreadLocal這個線程局部變量,這保證了它只會在單個線程中緩存,而且會在單次Json解析完成后移出緩存。見上文注釋1和注釋4。這是因為無限遞歸只會發(fā)生在單次Json解析中,而且Gson內(nèi)部已經(jīng)有了一個TypeAdapterde 全局緩存(typeTokenCache),見注釋0. ? 潛在的遞歸循環(huán): gson.getAdapter(type) ---> (ReflectiveTypeAdapterFactory)factory.create(this, type) ---> getBoundFields() ---> createBoundField() ---> (Gson)context.getAdapter(fieldType) 關(guān)于Gson自定義解析上文只講到了Gson自己內(nèi)部是如何實現(xiàn)Json解析的,其實Gson也提供了一些自定義解析的接口。主要是兩種: 自己實現(xiàn)繼承TypeAdapter 實現(xiàn)JsonSerializer/JsonDeserializer接口 那么,兩者有什么區(qū)別呢? 追求效率更高,選第一種,想要操作更簡單,實現(xiàn)更靈活,選第二種。 為什么這么說?舉個例子,假設(shè)我們需要為Article這個JavaBean自定義解析,如果我們選擇繼承TypeAdapter的話,需要先實現(xiàn)TypeAdapter,然后注冊。 //繼承TypeAdapter,實現(xiàn)抽象方法 publicclassArticleTypeAdapterextendsTypeAdapter @Override publicvoidwrite(JsonWriterout,Articlevalue)throwsIOException{ //實現(xiàn)把Article中的實體數(shù)據(jù)的寫入到JsonWriter中,實現(xiàn)序列化 } @Override publicArticleread(JsonReaderin)throwsIOException{ //需要創(chuàng)建Article對象 //把JsonReader中的json串讀出來,并設(shè)置到Article對象中 returnnull; } } ... ... //注冊 GsonmGson=newGsonBuilder() .registerTypeAdapter(Article.class,newArticleTypeAdapter<>())//實際上注冊到Gson的factories列表中 .create(); 這樣就實現(xiàn)了自定義的Json解析,這種方式的讀寫效率很高,但是不太靈活,因為必須要同時實現(xiàn)序列化和反序列化的工作。 而實現(xiàn)JsonSerializer/JsonDeserializer接口這種方式相對更簡單 //JsonSerializer(json序列話)/JsonDeserializer(反序列化)可按需實現(xiàn) publicclassArticleTypeAdapterimplementsJsonDeserializer @Override publicArticledeserialize(JsonElementjson,TypetypeOfT,JsonDeserializationContextcontext)throwsJsonParseException{ //需要創(chuàng)建Article對象 //并從JsonElement中把封裝好的Json數(shù)據(jù)結(jié)構(gòu)讀出來,并設(shè)置到Article對象中 returnnull; } } //注冊 GsonmGson=newGsonBuilder() .registerTypeAdapter(Article.class,newArticleTypeAdapter<>())//實際上注冊到Gson的factories列表中 .create(); 我們可以看到,兩者的區(qū)別,是后者更加靈活,序列化/返序列化可按需選擇,而且它使用了JsonElement對Json數(shù)據(jù)進行再封裝,從而使我們操作Json數(shù)據(jù)更加簡單。不過正是因為使用了 JsonElement這種對Json數(shù)據(jù)再封裝的類,而不是更加原始的JsonReader導致了代碼執(zhí)行效率的降低。 如上圖所示,本質(zhì)上就是多了一個中間層,導致解析效率的降低。不過話說回來,只要不是非常大批量復雜結(jié)構(gòu)的連續(xù)解析,這種效率差異我們可以忽略不計,因此日常的開發(fā),大家通過JsonSerializer/JsonDeserializer接口來實現(xiàn)自定義解析是一個相對更好的選擇。