01,我前世今生都叫Gson。它是一个开源Java库。它的主要目的是将Java对象序列化为JSON字符串,或者将JSON字符串反序列化为Java对象。从我的名字,我们可以看出一些端倪,我不是默默无闻的,我出生在贵族家庭,父亲是谷歌,市值无比丰厚。当然,作为一个聪明人,我是有自知之明的。在爸爸的眼里,我不是最闪亮的明星。我来到这个世界纯属偶然。不管怎样,我爸是这样告诉我的。他总是说我是从河里捡来的,虽然我从来不相信。对于这件事,我向妈妈证实了,妈妈笑得合不拢嘴,说我太天真了。从小喜欢旅行,所以认识了很多同行,Jackson和Fastjson也在其中。说起杰克逊,我总会第一时间想到MJ,那个被上帝带走的流行天王。杰克逊在GitHub上有6.1k星。虽然他的粉丝没有我那么多,但是作为SpringBoot默认的JSON解析器,我还是很尊敬他的。Fastjson来自神秘的东方。虽然已经暴露了一些严重的漏洞,但这并不妨碍他成为最流行的JSON解析器。他的粉丝比我多,虽然我已经有超过18K的star了。外人总说我们是竞争对手,但我不得不告诉他们,我们三个人的关系好到几乎穿了同一条内裤。我们各有优势,Jackson运行时占用内存少,Fastjson更快,我可以处理任意Java对象,即使没有源代码。另外,我对泛型的支持也比较友好。02.添加依赖在使用我的API之前,需要将我添加到项目中。推荐使用Maven和Gradle。Maven:com.google.code.gsongson2.8.6Gradle:dependencies{implementation'com.google.code.gson:gson:2.8.6'}PS:Gradle是一个基于ApacheAnt和ApacheMaven概念的项目自动化构建工具。Gradle构建脚本是使用Groovy或Kotlin领域特定语言而不是传统的XML编写的。03.表演不是我想的那样,是真的。大量的测试证明我在处理JSON的时候性能还是很不错的。测试环境:双核,8G内存,64位Ubuntu操作系统(基于桌面应用的Linux发行版)测试结果:1)反序列化25M以上的字符串没有问题。2)可以序列化140万个对象的集合。3)可以反序列化一个包含87000个对象的集合。4)将字节数组和集合的反序列化限制从80K增加到超过11M。我已经为您编写了测试用例并将其放在GitHub上。不信可以去验证一下。https://github.com/google/gson/blob/master/gson/src/test/java/com/google/gson/metrics/PerformanceTest.java04,使用指南不是我吹的,是真的,我是还是很好用的,上手难度几乎为零。不信你可以试试。我有一个和我同名的女朋友,也叫Gson,她提供了我所有的主要功能。你可以用newGson()这种简单粗暴的方式来创建她,或者你可以打电话给一个叫GsonBuilder的老板,让他邮寄一个复制品,真的,我不会骗你的。我们先看一个序列化的例子。Gsongson=newGson();System.out.println(gson.toJson(18));System.out.println(gson.toJson("Silence"));System.out.println(gson.toJson(newInteger(18))));int[]values={18,20};System.out.println(gson.toJson(values));在闺蜜的帮助下,可以将基本数据类型int、字符串类型String、包装类型Integer、int数组等作为参数传递给toJson()方法,会返回一个JSON格式的字符串。让我们看一下输出:18"silent"18[18,20]让我们看一下反序列化示例。Gsongson=newGson();intone=gson.fromJson("1",int.class);Integertwo=gson.fromJson("2",Integer.class);Booleanfalse1=gson.fromJson("false",Boolean.class);Stringstr=gson.fromJson("\"望二\"",String.class);String[]anotherStr=gson.fromJson("[\"沉默\",\"望二\"]",String[].class);System.out.println(一);System.out.println(二);System.out.println(false1);System.out.println(str);System.out.println(Arrays.toString(另一个Str));toJson()方法用于序列化,相应的fromJson()方法用于反序列化。但是在反序列化的时候需要指定参数的类型,是int还是Integer,是Boolean还是String,还是String数组。看一下输出:12false王二[沉默,王二]上面的例子比较简单,还是体现不出我的厉害。接下来我们定义一个类:publicclassWriter{privateintage=18;privateStringname="王二";privatetransientintsex=1;}然后我们序列化它:Writerwriter=newWriter();Gsongson=newGson();Stringjson=gson.toJson(writer);System.out.println(json);用法和前面一样简单,我们看一下输出结果:{"age":18,"name":"王二"}同理,可以对结果进行反序列化改造:Writerwriter1=gson.fromJson(json,作家类);这里有一些注意事项,我需要提醒你。1)建议使用private修改字段。2)不需要使用任何注解来指明哪些字段需要序列化,哪些字段不需要序列化。默认情况下,包括所有字段,以及从父类继承的字段。3)如果某个字段被transient关键字修饰,则不会参与序列化。4)如果某个字段的值为null,则序列化后的结果中不会显示。5)JSON中缺失的字段在反序列化后会被设置为默认值,引用数据类型默认值为null,数字类型默认值为0,boolean值默认值为false。接下来,让我们看一个序列化集合的例子。Listlist=newArrayList<>();list.add("好好学习");list.add("天天向上");Stringjson=gson.toJson(list);结果如下:["好好学习","天天向上"]反序列化的时候,也很简单。ListlistResult=gson.fromJson(json,List.class);结果如下:【好好学习,天天向上】我女朋友是一个很细心有爱心的人,当你调用toJson()方法序列化的时候,她会先判断null,防止抛出NPE,然后获取通过getClass()获取参数的类型,然后进行序列化。publicStringtoJson(Objectsrc){if(src==null){returntoJson(JsonNull.INSTANCE);}returntoJson(src,src.getClass());}但是什么?对于泛型,getClass()将丢失参数类型。看看下面的例子。publicclassFoo{T值;publicvoidset(Tvalue){this.value=value;}publicTget(){returnvalue;}publicstaticvoidmain(String[]args){Gsongson=newGson();Foofoo=newFoo();Barbar=newBar();foo.set(bar);Stringjson=gson.toJson(foo);}}classBar{privateintage=10;privateStringname="Turing";}调试的话,在方法里面输入toJson(),就可以了观察到的。foo的实际类型是Foo,但是我女朋友调用foo.getClass()时,她只得到了Foo,也就是说她并不知道foo的实际类型。序列化的时候还好,反序列化的时候就无能为力了。Foofoo1=gson.fromJson(json,foo.getClass());Barbar1=foo1.get();这段代码运行时报错。Exceptioninthread"main"java.lang.ClassCastException:classcom.google.gson.internal.LinkedTreeMapcannotbecasttoclasscom.itwanger.gson.Bar(com.google.gson.internal.LinkedTreeMapandcom.itwanger.gson.Barareinunnamedmoduleofloader'app')atcom.itwanger.gson.Foo.main(Foo.java:36)默认会把泛型参数类型转换为LinkedTreeMap,这显然不是我们期待的Bar,闺蜜表示无奈。作为谷歌之子,“贵族”二字流淌在我的血液里。闺蜜无依无靠,我怎能忍受她的寂寞。于是,我在女友身上植入了另外两个方法,Type类型参数:toJson(Objectsrc,TypetypeOfSrc);TfromJson(Stringjson,TypetypeOfT);在这种情况下,你在序列化泛型的时候反序列化和反序列化时,你可以指定泛型的参数化类型。TypefooType=newTypeToken>(){}.getType();Stringjson=gson.toJson(foo,fooType);Foofoo1=gson.fromJson(json,fooType);Barbar1=foo1.get();debug如果进入toJson()方法查看,可以看到foo的真实类型。fromJson()反序列化时类似这样。在这种情况下,可以通过foo1.get()访问bar1。看,我多周到,女朋友忍不住夸我!05.Handlingmixedtypes大家知道,Java不推荐使用混合类型,就是下面这种情况。Listlist=newArrayList();list.add("沉默之王2");list.add(18);list.add(newEvent("gson","google"));Event的定义如下:classEvent{privateStringname;privateStringsource;Event(Stringname,Stringsource){this.name=name;this.source=source;}}由于list没有指定具体类型,所以可以存放各种类型数据的。这样虽然省事,我闺蜜序列化的时候没问题,反序列化的时候就麻烦多了。Gsongson=newGson();Stringjson=gson.toJson(list);System.out.println(json);输出如下:["沉默之王二",18,{"name":"gson","source":"google"}]反序列化的时候,需要一点功夫才能得到Event对象。JsonParserparser=newJsonParser();JsonArrayarray=parser.parse(json).getAsJsonArray();Stringmessage=gson.fromJson(array.get(0),String.class);intnumber=gson.fromJson(array.get(1),int.class);Eventevent=gson.fromJson(array.get(2),Event.class);不可否认,JsonParser是我的前身。希望大家不要骂我没心没肺,真的不是我浮躁,是我们性格不合适。但是我们还是保持着朋友的关系,因为我们都没有错,只是代码更加规范,很少有开发者使用混合类型。06.个性化定制考虑到你是一个追求时尚的人,我一直对自己提出很高的要求,力求满足你的一切需求。这种高标准的要求,让女朋友对我又爱又恨。我爱的是我追求完美的态度;我讨厌的是,有时她不能如愿以偿,也无能为力。使用toJson()序列化Java对象时,返回的JSON字符串没有空格,非常紧凑。如果你想打印更漂亮的JSON,你需要打电话给一个叫GsonBuilder的人,让他做一些定制,然后寄给你一个叉子,就像我在操作方法中提到的那样。publicclassWriter{privateintage=18;privateStringname="沉默王二";publicstaticvoidmain(String[]args){Writerwriter=newWriter();Gsongson=newGson();Stringjson=gson.toJson(writer);System.out.println(json);Gsongson1=newGsonBuilder().setPrettyPrinting().create();StringjsonOutput=gson1.toJson(writer);System.out.println(jsonOutput);}}比较输出结果:{"age":18,"name":"沉默之王二"}{"age":18,"name":"沉默之王二"}通过setPrettyPrinting()自定义后,输出格式更加层次化和立体化,字段之间有空格和values,每个不同的字段之间也会有换行符。之前说过,默认情况下,我闺蜜在序列化的时候会忽略空值的字段。如果你不想这样,你也可以调用GsonBuilder。publicclassWriter{privateintage=18;privateStringname=null;publicstaticvoidmain(String[]args){Writerwriter=newWriter();Gsongson=newGson();Stringjson=gson.toJson(writer);System.out.println(json);Gsongson2=newGsonBuilder().serializeNulls().create();StringjsonOutput2=gson2.toJson(writer);System.out.println(jsonOutput2);}}比较输出结果:{"age":18}{"age":18,"name":null}通过serializeNulls()自定义后,序列化时不再忽略空值字段。也许,您想在序列化和反序列化时过滤一些字段。我也考虑过这个需求,给你准备了几个解决方案。您可以根据自己的口味选择适合自己的。第一种,通过Java修饰符。正如您之前看到的,使用transient关键字修饰的字段不会参与序列化和反序列化。同样,static关键字修饰的字段也不会。如果你想保留用这些关键字装饰的字段,你可以这样做。保持单一物种。Gsongson=newGsonBuilder().excludeFieldsWithModifiers(Modifier.TRANSIENT).create();保持多个。Gsongson=newGsonBuilder().excludeFieldsWithModifiers(Modifier.STATIC,Modifier.TRANSIENT,Modifier.VOLATILE).create();二、通过@Expose注解。要使用@Expose注解,你需要先这样做:Gsongson=newGsonBuilder().excludeFieldsWithoutExposeAnnotation().create();然后在需要序列化和反序列化的字段上加上@Expose注解。如果不是,该字段将被忽略。@Exposeprivateintage=18;07,如果你想了解更多,请访问我的GitHub主页:https://github.com/google/gson我会告诉你关于我的一切,毫无保留,除了我和我之间的一些秘密女朋友,只是为了帮助你。本文转载自微信公众号“沉默王二”,可通过以下二维码关注。转载本文请联系沉默王二公众号。