<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Gson:我爸是 Google

          共 8043字,需瀏覽 17分鐘

           ·

          2020-12-22 16:10

          01、前世今生

          我叫 Gson,是一款開源的 Java 庫(kù),主要用途為序列化 Java 對(duì)象為 JSON 字符串,或反序列化 JSON 字符串成 Java 對(duì)象。從我的名字上,就可以看得出一些端倪,我并非籍籍無(wú)名,我出身貴族,我爸就是 Google,市值富可敵國(guó)。

          當(dāng)然了,作為一個(gè)聰明人,我是有自知之明的,我在我爸眼里,我并不是最閃耀的那顆星。

          我來(lái)到這個(gè)世上,純屬一次意外,反正我爸是這樣對(duì)我說(shuō)的,他總說(shuō)我是從河邊撿回來(lái)的,雖然我一直不太相信。對(duì)于這件事,我向我媽確認(rèn)過(guò),她聽(tīng)完笑得合不攏嘴,說(shuō)我太天真。

          長(zhǎng)大后,我喜歡四處闖蕩,因此結(jié)識(shí)了不少同行,其中就有 Jackson 和 Fastjson。

          說(shuō)起 Jackson,我總能第一時(shí)間想到 MJ,那個(gè)被上帝帶走的流行天王。Jackson 在 GitHub 上有 6.1k 的 star,雖然他的粉絲數(shù)沒(méi)我多,但作為 Spring Boot 的默認(rèn) JSON 解析器,我非常地尊重他。

          Fastjson 來(lái)自神秘的東方,雖然爆出過(guò)一些嚴(yán)重的漏洞,但這并不妨礙他成為最受歡迎的 JSON 解析器,他的粉絲數(shù)比我還要多,盡管我已經(jīng)有超過(guò) 18K 的 star。

          外人總說(shuō)我們是競(jìng)爭(zhēng)對(duì)手,但我必須得告訴他們,我們仨的關(guān)系,好到就差穿同一條內(nèi)褲了。

          我們各有優(yōu)勢(shì),Jackson 在運(yùn)行時(shí)占用的內(nèi)存較少,F(xiàn)astjson 的速度更快,而我,可以處理任意的 Java 對(duì)象,甚至在沒(méi)有源代碼的情況下。另外,我對(duì)泛型的支持也更加的友好。

          02、添加依賴

          在使用我的 API 之前,需要先把我添加到項(xiàng)目當(dāng)中,推薦使用 ?Maven 和 Gradle 兩種形式。

          Maven:


          ????com.google.code.gson
          ????gson
          ????2.8.6

          Gradle:

          dependencies?{
          ??implementation?'com.google.code.gson:gson:2.8.6'
          }

          PS:Gradle 是一個(gè)基于 Apache Ant 和 Apache Maven 概念的項(xiàng)目自動(dòng)化建構(gòu)工具。Gradle 構(gòu)建腳本使用的是 Groovy 或 Kotlin 的特定領(lǐng)域語(yǔ)言來(lái)編寫的,而不是傳統(tǒng)的 XML。

          03、性能表現(xiàn)

          不是我覺(jué)得,是真的,通過(guò)大量的測(cè)試證明,我在處理 JSON 的時(shí)候性能還是很牛逼的。

          測(cè)試環(huán)境:雙核,8G 內(nèi)存,64 位的 Ubuntu 操作系統(tǒng)(以桌面應(yīng)用為主的 Linux 發(fā)行版)

          測(cè)試結(jié)果:

          1)在反序列化 25M 以上的字符串時(shí)沒(méi)有出現(xiàn)過(guò)任何問(wèn)題。

          2)可以序列化 140 萬(wàn)個(gè)對(duì)象的集合。

          3)可以反序列化包含 87000 個(gè)對(duì)象的集合。

          4)將字節(jié)數(shù)組和集合的反序列化限制從 80K 提高到 11M 以上。

          測(cè)試用例我已經(jīng)幫你寫好了,放在 GitHub 上,如果你不相信的話,可以驗(yàn)證一下。

          https://github.com/google/gson/blob/master/gson/src/test/java/com/google/gson/metrics/PerformanceTest.java

          04、使用指南

          不是我自吹自擂,是真的,我還是挺好用的,上手難度幾乎為零。如果你不相信話,可以來(lái)試試。

          我有一個(gè)女朋友,她的名字和我一樣,也叫 Gson,我的主要功能都由她來(lái)提供。你可以通過(guò) new Gson() 的這種簡(jiǎn)單粗暴的方式創(chuàng)建她,也可以打電話給一個(gè)叫 GsonBuilder 的老板,讓他郵寄一個(gè)復(fù)刻版過(guò)來(lái),真的,我不騙你。

          先來(lái)看一個(gè)序列化的例子。

          Gson?gson?=?new?Gson();
          System.out.println(gson.toJson(18));
          System.out.println(gson.toJson("沉默"));
          System.out.println(gson.toJson(new?Integer(18)));
          int[]?values?=?{?18,20?};
          System.out.println(gson.toJson(values));

          在我女朋友的幫助下,你可以將基本數(shù)據(jù)類型 int、字符串類型 String、包裝器類型 Integer、int 數(shù)組等等作為參數(shù),傳遞給 toJson() 方法,該方法將會(huì)返回一個(gè) JSON 形式的字符串。

          來(lái)看一下輸出結(jié)果:

          18
          "沉默"
          18
          [18,20]

          再來(lái)看一下反序列化的例子。

          Gson?gson?=?new?Gson();
          int?one?=?gson.fromJson("1",?int.class);
          Integer?two?=?gson.fromJson("2",?Integer.class);
          Boolean?false1?=?gson.fromJson("false",?Boolean.class);
          String?str?=?gson.fromJson("\"王二\"",?String.class);
          String[]?anotherStr?=?gson.fromJson("[\"沉默\",\"王二\"]",?String[].class);

          System.out.println(one);
          System.out.println(two);
          System.out.println(false1);
          System.out.println(str);
          System.out.println(Arrays.toString(anotherStr));

          toJson() 方法用于序列化,對(duì)應(yīng)的,fromJson() 方法用于反序列化。不過(guò),你需要在反序列化的時(shí)候,指定參數(shù)的類型,是 int 還是 Integer,是 Boolean 還是 String,或者 String 數(shù)組。

          來(lái)看一下輸出結(jié)果:

          1
          2
          false
          王二
          [沉默,?王二]

          上面的例子都比較簡(jiǎn)單,還體現(xiàn)不出來(lái)我的威力。

          下面,我們來(lái)自定義一個(gè)類:

          public?class?Writer?{
          ????private?int?age?=?18;
          ????private?String?name?=?"王二";
          ????private?transient?int?sex?=?1;
          }

          然后,我們來(lái)將其序列化:

          Writer?writer?=?new?Writer();
          Gson?gson?=?new?Gson();
          String?json?=?gson.toJson(writer);
          System.out.println(json);

          用法和之前一樣簡(jiǎn)單,來(lái)看一下輸出結(jié)果:

          {"age":18,"name":"王二"}

          同樣,可以將結(jié)果反序列化:

          Writer?writer1?=?gson.fromJson(json,?Writer.class);

          這里有一些注意事項(xiàng),我需要提醒你。

          1)推薦使用 private 修飾字段。

          2)不需要使用任何的注解來(lái)表明哪些字段需要序列化,哪些字段不需要序列化。默認(rèn)情況下,包括所有的字段,以及從父類繼承過(guò)來(lái)的字段。

          3)如果一個(gè)字段被 transient 關(guān)鍵字修飾的話,它將不參與序列化。

          4)如果一個(gè)字段的值為 null,它不會(huì)在序列化后的結(jié)果中顯示。

          5)JSON 中缺少的字段將在反序列化后設(shè)置為默認(rèn)值,引用數(shù)據(jù)類型的默認(rèn)值為 null,數(shù)字類型的默認(rèn)值為 0,布爾值默認(rèn)為 false。

          接下來(lái),來(lái)看一個(gè)序列化集合的例子。

          List?list?=new?ArrayList<>();
          list.add("好好學(xué)習(xí)");
          list.add("天天向上");
          String?json?=?gson.toJson(list);

          結(jié)果如下所示:

          ["好好學(xué)習(xí)","天天向上"]

          反序列化的時(shí)候,也很簡(jiǎn)單。

          List?listResult?=?gson.fromJson(json,List.class);

          結(jié)果如下所示:

          [好好學(xué)習(xí),?天天向上]

          我女朋友是一個(gè)很細(xì)心也很貼心的人,在你調(diào)用 toJson() 方法進(jìn)行序列化的時(shí)候,她會(huì)先判 null,防止拋出 NPE,再通過(guò) getClass() 獲取參數(shù)的類型,然后進(jìn)行序列化。

          public?String?toJson(Object?src)?{
          ????if?(src?==?null)?{
          ????????return?toJson(JsonNull.INSTANCE);
          ????}
          ????return?toJson(src,?src.getClass());
          }

          但是呢?對(duì)于泛型來(lái)說(shuō),getClass() 的時(shí)候會(huì)丟掉參數(shù)化類型。來(lái)看下面這個(gè)例子。

          public?class?Foo<T>?{
          ????T?value;

          ????public?void?set(T?value)?{
          ????????this.value?=?value;
          ????}

          ????public?T?get()?{
          ????????return?value;
          ????}

          ????public?static?void?main(String[]?args)?{
          ????????Gson?gson?=?new?Gson();
          ????????Foo?foo?=?new?Foo();
          ????????Bar?bar?=?new?Bar();
          ????????foo.set(bar);

          ????????String?json?=?gson.toJson(foo);
          ????}
          }

          class?Bar{
          ????private?int?age?=?10;
          ????private?String?name?=?"圖靈";
          }

          假如你 debug 的時(shí)候,進(jìn)入到 toJson() 方法的內(nèi)部,就可以觀察到。

          foo 的實(shí)際類型為 Foo,但我女朋友在調(diào)用 foo.getClass() 的時(shí)候,只會(huì)得到 Foo,這就意味著她并不知道 foo 的實(shí)際類型。

          序列化的時(shí)候還好,反序列化的時(shí)候就無(wú)能為力了。

          Foo?foo1?=?gson.fromJson(json,?foo.getClass());
          Bar?bar1?=?foo1.get();

          這段代碼在運(yùn)行的時(shí)候就報(bào)錯(cuò)了。

          Exception?in?thread?"main"?java.lang.ClassCastException:?class?com.google.gson.internal.LinkedTreeMap?cannot?be?cast?to?class?com.itwanger.gson.Bar?(com.google.gson.internal.LinkedTreeMap?and?com.itwanger.gson.Bar?are?in?unnamed?module?of?loader?'app')
          ?at?com.itwanger.gson.Foo.main(Foo.java:36)

          默認(rèn)情況下,泛型的參數(shù)類型會(huì)被轉(zhuǎn)成 LinkedTreeMap,這顯然并不是我們預(yù)期的 Bar,女朋友對(duì)此表示很無(wú)奈。

          作為 Google 的親兒子,我的血液里流淌著“貴族”二字,我又怎能忍心女朋友無(wú)助時(shí)的落寞。

          于是,我在女朋友的體內(nèi)植入了另外兩種方法,帶 Type 類型參數(shù)的:

          toJson(Object?src,?Type?typeOfSrc);
          ?T?fromJson(String?json,?Type?typeOfT);

          這樣的話,你在進(jìn)行泛型的序列化和反序列化時(shí),就可以指定泛型的參數(shù)化類型了。

          Type?fooType?=?new?TypeToken>()?{}.getType();
          String?json?=?gson.toJson(foo,fooType);
          Foo?foo1?=?gson.fromJson(json,?fooType);
          Bar?bar1?=?foo1.get();

          debug 進(jìn)入 toJson() 方法內(nèi)部查看的話,就可以看到 foo 的真實(shí)類型了。

          fromJson() 在反序列化的時(shí)候,和此類似。

          這樣的話,bar1 就可以通過(guò) foo1.get() 到了。

          瞧,我考慮得多周全,女朋友都忍不住夸我了!

          05、處理混合類型

          你知道的,Java 不建議使用混合類型,也就是下面這種情況。

          List?list?=?new?ArrayList();
          list.add("沉默王二");
          list.add(18);
          list.add(new?Event("gson",?"google"));

          Event 的定義如下所示:

          class?Event?{
          ????private?String?name;
          ????private?String?source;
          ????Event(String?name,?String?source)?{
          ????????this.name?=?name;
          ????????this.source?=?source;
          ????}
          }

          由于 list 沒(méi)有指定具體的類型,因此它里面可以存放各種類型的數(shù)據(jù)。這樣雖然省事,我女朋友在序列化的時(shí)候也沒(méi)問(wèn)題,但反序列化的時(shí)候就要麻煩多了。

          Gson?gson?=?new?Gson();
          String?json?=?gson.toJson(list);
          System.out.println(json);

          輸出結(jié)果如下所示:

          ["沉默王二",18,{"name":"gson","source":"google"}]

          反序列化的時(shí)候,就需要花點(diǎn)心思才能拿到 Event 對(duì)象。

          JsonParser?parser?=?new?JsonParser();
          JsonArray?array?=?parser.parse(json).getAsJsonArray();
          String?message?=?gson.fromJson(array.get(0),?String.class);
          int?number?=?gson.fromJson(array.get(1),?int.class);
          Event?event?=?gson.fromJson(array.get(2),?Event.class);

          承認(rèn)了,JsonParser 是我的前任。希望你不要噴我渣男,真不是我花心,是因?yàn)槲覀冃愿裆嫌行┎惶m合。但我們?nèi)匀槐3种笥训年P(guān)系,因?yàn)槲覀冋l(shuí)都沒(méi)有錯(cuò),只是代碼更加規(guī)范了,已經(jīng)很少有開發(fā)者使用混合類型了。

          06、個(gè)性化定制

          考慮到你是一個(gè)追求時(shí)髦的人,我一直對(duì)自己要求很高,力爭(zhēng)能夠滿足你的所有需求。這種高標(biāo)準(zhǔn)的要求,讓我女朋友對(duì)我是又愛(ài)又恨。

          愛(ài)的是,我這種追求完美的態(tài)度;恨的是,她有時(shí)候力不從心,幫不上忙。

          使用 toJson() 序列化 Java 對(duì)象時(shí),返回的 JSON 字符串中沒(méi)有空格,很緊湊。如果你想要打印更漂亮的 JSON 格式,你需要打電話給一個(gè)叫 GsonBuilder 的老板,讓他進(jìn)行一些定制,然后再把復(fù)刻版郵寄給你,就像我在使用指南中提到的那樣。

          public?class?Writer?{
          ????private?int?age?=?18;
          ????private?String?name?=?"沉默王二";

          ????public?static?void?main(String[]?args)?{
          ????????Writer?writer?=?new?Writer();
          ????????Gson?gson?=?new?Gson();
          ????????String?json?=?gson.toJson(writer);
          ????????System.out.println(json);

          ????????Gson?gson1?=?new?GsonBuilder().setPrettyPrinting().create();
          ????????String?jsonOutput?=?gson1.toJson(writer);
          ????????System.out.println(jsonOutput);
          ????}
          }

          來(lái)對(duì)比一下輸出結(jié)果:

          {"age":18,"name":"沉默王二"}
          {
          ??"age":?18,
          ??"name":?"沉默王二"
          }

          通過(guò) setPrettyPrinting() 定制后,輸出的格式更加層次化、立體化,字段與值之間有空格,每個(gè)不同的字段之間也會(huì)有換行。

          之前提到了,默認(rèn)情況下,我女朋友在序列化的時(shí)候會(huì)忽略 null 值的字段,如果不想這樣的話,同樣可以打電話給 GsonBuilder。

          public?class?Writer?{
          ????private?int?age?=?18;
          ????private?String?name?=?null;

          ????public?static?void?main(String[]?args)?{
          ????????Writer?writer?=?new?Writer();
          ????????Gson?gson?=?new?Gson();
          ????????String?json?=?gson.toJson(writer);
          ????????System.out.println(json);

          ????????Gson?gson2?=?new?GsonBuilder().serializeNulls().create();
          ????????String?jsonOutput2?=?gson2.toJson(writer);
          ????????System.out.println(jsonOutput2);
          ????}
          }

          來(lái)對(duì)比一下輸出結(jié)果:

          {"age":18}
          {"age":18,"name":null}

          通過(guò) serializeNulls() 定制后,序列化的時(shí)候就不會(huì)再忽略 null 值的字段。

          也許,你在序列化和反序列化的時(shí)候想要篩選一些字段,我也考慮到這種需求了,特意為你準(zhǔn)備了幾種方案,你可以根據(jù)自己的口味挑選適合你的。

          第一種,通過(guò) Java 修飾符

          你之前也看到了,使用 transient 關(guān)鍵字修飾的字段將不會(huì)參與序列化和反序列化。同樣的,static 關(guān)鍵字修飾的字段也不會(huì)。如果你想保留這些關(guān)鍵字修飾的字段,可以這樣做。

          保留單種。

          Gson?gson?=?new?GsonBuilder().excludeFieldsWithModifiers(Modifier.TRANSIENT).create();

          保留多種。

          Gson?gson?=?new?GsonBuilder()
          ????.excludeFieldsWithModifiers(Modifier.STATIC,?Modifier.TRANSIENT,?Modifier.VOLATILE)
          ????.create();

          第二種,通過(guò) @Expose 注解。

          要使用 @Expose 注解,你需要先這樣做:

          Gson?gson?=?new?GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();

          再在需要序列化和反序列化的字段上加上 @Expose 注解,如果沒(méi)加的話,該字段將會(huì)被忽略。

          @Expose
          private?int?age?=?18;

          07、心聲

          如果你還想了解更多的話,請(qǐng)來(lái)參觀我的 GitHub 主頁(yè):

          https://github.com/google/gson

          我會(huì)向你坦露我的一切,毫不保留的,除了我和女朋友之間的一些秘密,只為能夠幫助到你。

          如果你覺(jué)得我有點(diǎn)用的話,不妨點(diǎn)個(gè)贊,留個(gè)言,see you。

          瀏覽 38
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费av网站在线观看 | 波多野结衣在线网站 | 国产精品一区二区三区高潮 | 国产日韩一级片 | 不要钱的黄视频免费看在线 |