Gson用户指南

概况

Gson是一个Java库,它可以用来把Java对象转换为JSON表达式,也可以反过来把JSON字符串转换成与之相同的Java对象
Gson可以对任何Java对象使用包括那些你没有源码的对象,但已存在的对象

Gson的目标

  • 提供简单易用的机制类似于toString()和构造器(工厂模式)用来进行Java和JSON互相转换
  • 允许把预先存在但无法修改的对象转换为JSON或从JSON转换
  • 允许对象的自定义表示
  • 支持任何复杂的对象
  • 生成紧凑易读的JSON输出

Gson的性能和可延展性

这里提供的一些参数是从我们的一台笔记本(双核AMD皓龙处理器,8GB RAM,64位Ubuntu系统)上运行了很多的测试用例中获取的,你也可以用PerformanceTest类来重新运行这些测试案例

  • 对于字符串:反序列化超过25MB的字符串没有任何问题(可以查看PerformanceTest下的方法disabled_testStringDeserializationPerformance)

  • 对于大型集合:

    • 序列化过一个拥有1400万个对象的集合(可以查看PerformanceTest下的disabled_testLargeCollectionSerialization方法)
      -反序列化过一个拥有8.7万个对象的集合(可以查看PerformanceTest下的disabled_testLargeCollectionDeserialization方法)
      -Gson的1.4版本将字节数组和集合的反序列化最大值从80KB提高到了11MB

提示:运行这些测试用例时要删除disabled_前缀,我们使用这些前缀是为了在每次运行JUnit测试时避免运行到上述例子

Gson的用户

Gson原本是创造给Google内部人员使用并运用在目前的的很多Google项目中。现在被很多公共项目和公司所使用

使用Gson

Gson的主要用到的类是Gson,你可以直接通过调用new Gson()来生成,也可以用类GsonBuilder来创建Gson实例,这样创建就可以自主进行参数设置类似于版本控制之类

Gson实例不会保留任何状态当你调用Json操作时,所以你可以随意的重用一个对象操作多个Json序列化和反序列化操作

Android:在Gradle上使用Gson

dependencies {
    implementation 'com.google.code.gson:gson:2.8.5'
}

在Maven上使用Gson

要在Maven2/3中使用Gson,你可以在Maven库中找到Gson合适的版本添加到下面的dependency

<dependencies>
    <!--  Gson: Java to Json conversion -->
    <dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
      <version>2.8.5</version>
      <scope>compile</scope>
    </dependency>
</dependencies>

这样你的maven项目就可以用Gson了

基本例子

// 序列化
Gson gson = new Gson();
gson.toJson(1);            // ==> 1
gson.toJson("abcd");       // ==> "abcd"
gson.toJson(new Long(10)); // ==> 10
int[] values = { 1 };
gson.toJson(values);       // ==> [1]

// 反序列化
int one = gson.fromJson("1", int.class);
Integer one = gson.fromJson("1", Integer.class);
Long one = gson.fromJson("1", Long.class);
Boolean false = gson.fromJson("false", Boolean.class);
String str = gson.fromJson("\"abc\"", String.class);
String[] anotherStr = gson.fromJson("[\"abc\"]", String[].class);

关于对象的例子

class BagOfPrimitives {
  private int value1 = 1;
  private String value2 = "abc";
  private transient int value3 = 3;
  BagOfPrimitives() {
    // no-args constructor
  }
}

// 序列化
BagOfPrimitives obj = new BagOfPrimitives();
Gson gson = new Gson();
String json = gson.toJson(obj);  

// ==> json is {"value1":1,"value2":"abc"}

注意你不能序列化有循环调用的对象,不然会返回一个无限递归的结果

// 反序列化
BagOfPrimitives obj2 = gson.fromJson(json, BagOfPrimitives.class);
// ==> obj2 is just like obj
对象的细节
  • 对象里使用private是完全可以运行的,而且我们推荐你这么做
  • 不用声明什么区域需要被序列化或者反序列化,当前类的所有区域(包括所有的超类)都被默认包括进去
  • 如果字段被标记为瞬态,(默认情况下)会被忽略不会被包括在JSON序列化或者反序列化中
  • 这实现这么处理的Null值(?)
    • 序列化时,输出中省略了空字段。
    • 当反序列化时,当类中的区域在JSON结果中找不到时默认会设置:对象会设置为null,数字类型会设置为0,布尔类型会设置为false
  • 如果类型是syntactic,会被忽略,不被包含在JSON序列化或反序列化
  • 与内部类,匿名类和本地类中的外部类对应的字段将被忽略,并且不包括在序列化或反序列化中。
嵌套类(包含内部类)

Gson可以简单的序列化静态嵌套类

Gson 还可以反序列化静态嵌套类。但是,Gson 不能自动反序列化纯内部类,因为它们的 no-args 构造函数还需要对反序列化时不可用的包含 Object 的引用。您可以通过使内部类静态或为其提供自定义 InstanceCreator 来解决此问题
这是一个例子:

public class A { 
  public String a; 

  class B { 

    public String b; 

    public B() {
      // No args constructor for B
    }
  } 
}

注意:上述 B 类不能(默认情况下)使用 Gson 序列化。

{"b":"abc"}由于 B 类是一个内部类,Gson 不能反序列化为 B 的实例。如果它被定义为静态类 B,那么 Gson 就能够反序列化字符串。另一种解决方案是为 B 编写自定义实例创建器。

public class InstanceCreatorForB implements InstanceCreator<A.B> {
  private final A a;
  public InstanceCreatorForB(A a)  {
    this.a = a;
  }
  public A.B createInstance(Type type) {
    return a.new B();
  }
}

上述代码可以运行但是不推荐

数组例子
Gson gson = new Gson();
int[] ints = {1, 2, 3, 4, 5};
String[] strings = {"abc", "def", "ghi"};

// Serialization
gson.toJson(ints);     // ==> [1,2,3,4,5]
gson.toJson(strings);  // ==> ["abc", "def", "ghi"]

// Deserialization
int[] ints2 = gson.fromJson("[1,2,3,4,5]", int[].class); 
// ==> ints2 will be same as ints

我们也支持多尺寸数组和任何复杂的元素类型

集合例子
Gson gson = new Gson();
Collection<Integer> ints = Lists.immutableList(1,2,3,4,5);

// Serialization
String json = gson.toJson(ints);  // ==> json is [1,2,3,4,5]

// Deserialization
Type collectionType = new TypeToken<Collection<Integer>>(){}.getType();
Collection<Integer> ints2 = gson.fromJson(json, collectionType);
// ==> ints2 is same as int

可怕的现象:注意到我们怎么定义collection类型的吗?不幸的是,在Java里不能这么做

集合的限制
Gson可以序列化任意形式的集合但是不能把它反序列,因为没法给用户表明结果对象(?),反而,当反序列化时,集合必须是具体和通用的类型,大家都知道,当遵循良好的编码习惯就很少出现问题

当序列化和反序列化泛型

当你调用toJson(obj),Gson会调用obj.getClass()来获取区域的信息去序列化,同样,你可以通过MyClass.class对象的fromJson(json, MyClass.class)方法.如果对象里没有泛型这么做也可以。但是,如果你的对象里有泛型,这么做泛型会丢失,因为Java的类型擦除,这有个例子来说明这点

class Foo<T> {
  T value;
}
Gson gson = new Gson();
Foo<Bar> foo = new Foo<Bar>();
gson.toJson(foo); // May not serialize foo.value correctly

gson.fromJson(json, foo.getClass()); // Fails to deserialize foo.value as Bar

上述代码想赋予value的类型Bar但失败了因为Gson调用了list.getClass()方法去获取这个类的信息,但是返回一个纯类Foo.class。这就是说Gson没有方法知道你的对象的类型是Foo<Bar>而不是Foo

你可以通过确定正确的参数来代替泛型可以解决上述问题,你也可以用TypeToken

Type fooType = new TypeToken<Foo<Bar>>() {}.getType();
gson.toJson(foo, fooType);

gson.fromJson(json, fooType);

惯用方法是获取fooType来实际定义一个匿名内部类来包含用来返回整个参数类型的getType()方法

序列化和反序列化带有任意类型对象的集合

有时候你需要处理带有杂乱类型的JSON数组,像是['hello',5,{name:'GREETINGS',source:'guest'}]
与之相等的Collection包含:

Collection collection = new ArrayList();
collection.add("hello");
collection.add(5);
collection.add(new Event("GREETINGS", "guest"));

Event定义成:

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

你可以直接用Gson去序列化集合而且不用做其他任何事情,toJson(collection)会写出你期待的输出

但是,反序列化fromJson(json, Collection.class)无法工作,因为 Gson 无法知道如何将输入映射到类型。Gson 要求您提供集合类型的通用版本fromJson()。所以,你有三个选择:

  1. 使用 Gson 的解析器 API(低级流解析器或 DOM 解析器 JsonParser)来解析数组元素,然后Gson.fromJson()在每个数组元素上使用。这是首选方法。这是一个演示如何执行此操作的示例

  2. 注册一个类型适配器Collection.class,查看每个数组成员并将它们映射到适当的对象。这种方法的缺点是它会搞砸 Gson 中其他集合类型的反序列化。

  3. 注册一个类型的适配器MyCollectionMemberType,并使用fromJson()Collection<MyCollectionMemberType>

仅当数组显示为顶级元素或者您可以更改将集合保持为类型的字段类型时,此方法才可用Collection<MyCollectionMemberType>

内置的序列化器和反序列化器

Gson 有常用类的内置序列化器和反序列化器,其默认表示可能不合适。以下是此类的列表:

  1. java.net.URL 把它与字符串匹配 "https://github.com/google/gson/"
  2. java.net.URI 把它与字符串匹配 "/google/gson/"

您还可以在此页面找到一些常用类的源代码,例如 JodaTime 。

自定义序列化和反序列化

有时默认表示不是您想要的。处理库类(DateTime 等)时经常会出现这种情况。Gson 允许您注册自己的自定义序列化程序和反序列化程序。这是通过定义两部分来完成的:

  • Json Serializers:需要为对象定义自定义序列化

  • Json Deserializers:需要为类型定义自定义反序列化

  • Instance Creators:如果 no-args 构造函数可用或注册了反序列化器,则不需要

GsonBuilder gson = new GsonBuilder();
gson.registerTypeAdapter(MyType2.class, new MyTypeAdapter());
gson.registerTypeAdapter(MyType.class, new MySerializer());
gson.registerTypeAdapter(MyType.class, new MyDeserializer());
gson.registerTypeAdapter(MyType.class, new MyInstanceCreator());

registerTypeAdapter 调用检查类型适配器是否实现了多个这些接口并为所有接口注册它。

编写序列化程序

以下是如何为 JodaTime DateTime类编写自定义序列化程序的示例。

private class DateTimeSerializer implements JsonSerializer<DateTime> {
  public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context) {
    return new JsonPrimitive(src.toString());
  }
}

Gson在序列化过程中遇到DateTime对象时调用serialize()

编写烦序列化程序

下面是如何为JodaTime DateTime类编写自定义反序列化器的示例。

private class DateTimeDeserializer implements JsonDeserializer<DateTime> {
  public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
      throws JsonParseException {
    return new DateTime(json.getAsJsonPrimitive().getAsString());
  }
}

当需要将JSON字符串片段反序列化为DateTime对象时,Gson调用deserialize

序列化器和反序列化器的细节

通常,您希望为与原始类型对应的所有泛型类型注册单个处理程序

  • 例如,假设您有一个Id用于 id 表示 / 转换的类(即内部表示与外部表示)。
  • Id<T> 对所有泛型类型具有相同序列化的类型
    • 基本上写出 id 值
  • 反序列化非常相似但不完全相同
    • 需要调用new Id(Class<T>, String)哪个返回一个实例Id<T>

Gson 支持为此注册一个处理程序。您还可以为特定的泛型类型注册特定的处理程序(比如Id<RequiresSpecialHandling>需要特殊处理)。在Type该参数toJson()fromJson()包含的通用类型的信息来帮助你编写对应于同一原始类型的所有泛型类型单一的处理程序。

编写实例创建器

在反序列化 Object 时,Gson 需要创建该类的默认实例。用于序列化和反序列化的良好的类应该具有无参数构造函数。

  • 与用public还是private无关

通常,在处理未定义无参数构造函数的库类时,需要实例创建器

实例创建器示例

private class MoneyInstanceCreator implements InstanceCreator<Money> {
  public Money createInstance(Type type) {
    return new Money("1000000", CurrencyCode.USD);
  }
}

类型可以是相应的泛型类型

  • 对于调用需要特定泛型类型信息的构造函数非常有用
  • 例如,如果Id类存储了正在为其创建 Id 的类

参数化类型的 InstanceCreator

有时,您尝试实例化的类型是参数化类型。通常,这不是问题,因为实际的实例是原始类型。这是一个例子:

class MyList<T> extends ArrayList<T> {
}

class MyListInstanceCreator implements InstanceCreator<MyList<?>> {
    @SuppressWarnings("unchecked")
  public MyList<?> createInstance(Type type) {
    // No need to use a parameterized list since the actual instance will have the raw type anyway.
    return new MyList();
  }
}

但是,有时您需要根据实际参数化类型创建实例。在这种情况下,您可以使用传递给createInstance方法的 type 参数。这是一个例子:

public class Id<T> {
  private final Class<T> classOfId;
  private final long value;
  public Id(Class<T> classOfId, long value) {
    this.classOfId = classOfId;
    this.value = value;
  }
}

class IdInstanceCreator implements InstanceCreator<Id<?>> {
  public Id<?> createInstance(Type type) {
    Type[] typeParameters = ((ParameterizedType)type).getActualTypeArguments();
    Type idType = typeParameters[0]; // Id has only one parameterized type T
    return Id.get((Class)idType, 0L);
  }
}

在上面的示例中,如果没有实际传入参数化类型的实际类型,则无法创建 Id 类的实例。我们通过使用传递的方法参数来解决这个问题typetype在这种情况下,对象是 Java 参数化类型表示Id<Foo>实际实例应绑定到的位置Id<Foo>。由于Idclass 只有一个参数化类型参数,T我们使用返回的类型数组的第 0 个元素,在这种情况下getActualTypeArgument()它将保存Foo.class

JSON输出形式:紧凑输出VS优雅输出

Gson 提供的默认 JSON 输出是紧凑的 JSON 格式。这意味着输出 JSON 结构中不会有任何空格。因此,JSON 输出中的字段名称及其值,对象字段和数组内的对象之间不会有空格。同样,输出中将忽略 “null” 字段(注意:null 值仍将包含在对象的集合 / 数组中)。有关配置 Gson 以输出所有空值的信息,请参阅Null 对象支持部分。

如果要使用 “优雅输出” 功能,则必须使用GsonBuilder来创建Gson实例。JsonFormatter没有在我们的公共 API 公开,所以用户无法为JSON的输出形式做配置和调整,目前,我们只提供JsonPrintFormatter默认行长度为 80 个字符,2 个字符缩进和 4 个字符右边距。

以下是一个示例,说明如何配置Gson实例以使用默认值JsonPrintFormatter而不是JsonCompactFormatter

Gson gson = new GsonBuilder().setPrettyPrinting().create();
String jsonOutput = gson.toJson(someObject);

空对象支持
在 Gson 中实现的默认行为null是忽略对象字段。这允许更紧凑的输出格式;但是,用户必须为这些字段定义默认值,因为 JSON 格式将转换回其 Java 表单。

以下是配置Gson实例输出 null 的方法:

Gson gson = new GsonBuilder().serializeNulls().create();

注意:在使用 Gson 序列化 null 时,它会向JsonElement结构添加JsonNull元素。因此,此对象可用于自定义序列化 / 反序列化。

这是一个例子:

public class Foo {
  private final String s;
  private final int i;

  public Foo() {
    this(null, 5);
  }

  public Foo(String s, int i) {
    this.s = s;
    this.i = i;
  }
}

Gson gson = new GsonBuilder().serializeNulls().create();
Foo foo = new Foo();
String json = gson.toJson(foo);
System.out.println(json);

json = gson.toJson(null);
System.out.println(json);

输出是:

{"s":null,"i":5}
null

版本控制支持

使用@Since注释可以维护同一对象的多个版本。此批注可用于类,字段以及将来的发行版中的方法。要利用此功能,必须将Gson实例配置为忽略任何大于某个版本号的字段 / 对象。如果没有在Gson实例上设置任何版本,则无论版本如何,它都将序列化和反序列化所有字段和类。

public class VersionedClass {
  @Since(1.1) private final String newerField;
  @Since(1.0) private final String newField;
  private final String field;

  public VersionedClass() {
    this.newerField = "newer";
    this.newField = "new";
    this.field = "old";
  }
}

VersionedClass versionedObject = new VersionedClass();
Gson gson = new GsonBuilder().setVersion(1.0).create();
String jsonOutput = gson.toJson(someObject);
System.out.println(jsonOutput);
System.out.println();

gson = new Gson();
jsonOutput = gson.toJson(someObject);
System.out.println(jsonOutput);

输出是:

{"newField":"new","field":"old"}

从序列化和反序列化中排除字段

Gson 支持许多排除顶级类,字段和字段类型的机制。下面列出的是可插入的机制,允许字段和类排除。如果以下机制都不能满足您的需求,那么您始终可以使用自定义序列化程序和反序列化程序

Java 修饰符排除

默认情况下,如果将字段标记为transient,则将排除该字段。同样,如果某个字段被标记为static默认情况下将被排除。如果要包含一些瞬态字段,则可以执行以下操作:

import java.lang.reflect.Modifier;
Gson gson = new GsonBuilder()
    .excludeFieldsWithModifiers(Modifier.STATIC)
    .create();

注意:您可以为方法excludeFieldsWithModifiers提供任意数量的Modifier常量。例如:

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

GSON 的 @Expose

此功能提供了一种方法,您可以将要排除的对象的某些字段标记为序列化和反序列化为 JSON。要使用此批注,必须使用创建 Gson new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()。创建的 Gson 实例将排除类中未标注@Expose注释的所有字段。

用户定义的排除策略

如果排除字段和类类型的上述机制对您不起作用,那么您始终可以编写自己的排除策略并将其插入 Gson。有关ExclusionStrategy更多信息,请参阅 JavaDoc。

以下示例显示如何排除标记有特定@Foo注释的字段,并排除类的顶级类型(或声明的字段类型)String

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Foo {
  // Field tag only annotation
}

public class SampleObjectForTest {
  @Foo private final int annotatedField;
  private final String stringField;
  private final long longField;
  private final Class<?> clazzField;

  public SampleObjectForTest() {
    annotatedField = 5;
    stringField = "someDefaultValue";
    longField = 1234;
  }
}

public class MyExclusionStrategy implements ExclusionStrategy {
  private final Class<?> typeToSkip;

  private MyExclusionStrategy(Class<?> typeToSkip) {
    this.typeToSkip = typeToSkip;
  }

  public boolean shouldSkipClass(Class<?> clazz) {
    return (clazz == typeToSkip);
  }

  public boolean shouldSkipField(FieldAttributes f) {
    return f.getAnnotation(Foo.class) != null;
  }
}

public static void main(String[] args) {
  Gson gson = new GsonBuilder()
      .setExclusionStrategies(new MyExclusionStrategy(String.class))
      .serializeNulls()
      .create();
  SampleObjectForTest src = new SampleObjectForTest();
  String json = gson.toJson(src);
  System.out.println(json);
}

输出是:

{"longField":1234}

JSON 字段命名支持

Gson 支持一些预定义的字段命名策略,以将标准 Java 字段名称(即以小写字母 --- 开头的驼峰名称sampleFieldNameInJava)转换为 Json 字段名称(即sample_field_name_in_javaSampleFieldNameInJava)。有关预定义命名策略的信息,请参阅FieldNamingPolicy类。

它还具有基于注释的策略,允许用户基于每个字段定义自定义名称。请注意,基于注释的策略具有字段名称验证,如果提供了无效的字段名称作为注释值,则会引发 “运行时” 异常。

以下是如何使用两个 Gson 命名策略功能的示例:

private class SomeObject {
  @SerializedName("custom_naming") private final String someField;
  private final String someOtherField;

  public SomeObject(String a, String b) {
    this.someField = a;
    this.someOtherField = b;
  }
}

SomeObject someObject = new SomeObject("first", "second");
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create();
String jsonRepresentation = gson.toJson(someObject);
System.out.println(jsonRepresentation);

输出是:

{"custom_naming":"first","SomeOtherField":"second"}

如果您需要自定义命名策略(请参阅此讨论),可以使用@SerializedName的注解。

在自定义序列化器和反序列化器之间共享状态

有时您需要在自定义序列化器 / 反序列化器之间共享状态(请参阅此讨论)。您可以使用以下三种策略来完成此任务:

  1. 在静态字段中存储共享状态
  2. 将序列化器 / 反序列化器声明为父类型的内部类,并使用父类型的实例字段来存储共享状态
  3. 使用 Java ThreadLocal

1 和 2 不是线程安全选项,但 3 是。

除了 Gson 的对象模型和数据绑定之外,您还可以使用 Gson 读取和写入。您还可以组合流和对象模型访问,以获得两种方法中的最佳方法。

在设计 Gson 时遇到的问题

有关我们在设计 Gson 时遇到的问题的讨论,请参阅Gson 设计文档。它还包括 Gson 与可用于 Json 转换的其他 Java 库的比较。

Gson 未来的改进

有关最新的更新计划或者如果你有新的建议,请参阅项目网站下的 Issues。部分

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容

  • 为了更好的学习Gson,特将Gson User Guide翻译如下。由于本人英文水平有限,如有错误,还请指正,谢谢...
    WeberLisper阅读 6,715评论 0 6
  • 1.概述2.Gson的目标3.Gson的性能和扩展性4.Gson的使用者5.如何使用Gson 通过Maven来使用...
    人失格阅读 14,204评论 2 18
  • 前言 “设计模式”这四个字,对于使用面向对象语言进行软件开发的程序员来说绝不会陌生,不过对于很多经验尚浅的而言也仅...
    Caltortoise阅读 832评论 0 3
  • Android中Gson的使用 1 简介 Gson是一个Java库,作用是将Java对象转换成它对应的JSON表示...
    LuckyXiang阅读 19,764评论 2 3
  • 这是我姥爷给我讲过的故事—— 说,很久以前,有一个年轻人叫张三,父母死的早,家里穷,没有媳妇,靠给地主打短工过日子...
    乡上阅读 441评论 1 1