Gson 使用篇

Gson 使用篇

开篇:在使用Gson之前,我们先聊一下Json, 虽然大部分人都用过,经常用,但有时候并不会太注意细节,写这篇博客也是为了更清晰的了解Gson是如何解析Json,这篇博客主要讲解Json的语法,以及使用Gson如何解析Json,下篇博客讲解Gson解析Json的主要流程及原理,网上很多类似的博客,这里也算自己学习的一个记录,总结。

一. Json 是什么?

Json 是诸多序列化方案的一种,是一种轻量级的数据交换格式,主要用于数据的网络传输,本地存储,数据标记使用。

二. Json 语法格式

    #### 2.1 Json构建的两种结构
  1. 键/值对的集合(A collection of name/value pairs). 不同的语言中,它被理解为对象(Object), 记录(record), 结构(struct), 字典(dictionary),哈希表(hash table), 有键列表(keyed list), 或者关联数组(associative array)

  2. 值的有序列表(An ordered list of values)。 在大部分语言中,它被理解为数组(array).

  3. 我们可以理解为两种构造,一种是对象,一种是数组(数组中包含的还是对象)

  4. Json语法-Object

    开始是一个无序的“key/value”的集合,一个对象以"{"(左括号)开始, “}”(右括号结束)。

    每个“key”后面跟一个":"(冒号); “key/value” 对之间使用 “,”(逗号)分隔,格式如下图

    Gson 使用篇

json Object的常见的格式如下:

// 这里整体算是一个Object
{
	"name": "英语",        // 这里是一个key/Value 对, 两个key/value对之间使用  "," 逗号隔开            
    "score": 99
}
  1. Json语法-array

    数组的值(value)的有序集合,其中每个value都是一个Object。一个数组以"["(左中括号)开始,以"]"(右中括号)结束。值之间使用","(逗号)分割。

    格式如下图:

    Gson 使用篇

    json array的常见格式如下:

    // 最外层的这个{ 是一个Object 它包含了一个名为array的数组,array数组有两个value(每个value又是一个Object)
    {              
        "array":[
            {
                "name":"name",
                "age":18
            },
            {
                "name":"yingyu",
                "score":20
            }
        ]
    }
    
    1. Json语法-value

      值(value) 可以是双引号括起来的字符串(string)、数值(number)、‘true’、‘false’、‘null’、对象(Object)或者数组(array)。这些结构都可以嵌套。

      如前面,4, 5所述的json语法一个对象(Object)可以包含一个或多个数组,一个数组(array)也可以包含多个对象(Object)

      value的类型如下图:

      Gson 使用篇

  2. Json语法-string
    字符串(string)是由双引号包围的任意数量的Unicode字符的集合,使用反斜线转义。

    如下图:

    Gson 使用篇

  3. Json语法-number

    数值(number)也与C或者Java的数值非常相似。除去未曾使用的八进制和十六进制格式。出去一些编码细节

    如下图:

    Gson 使用篇

三. Json 特点

  1. 读写速度快
  2. 解析简单
  3. 轻量级
  4. 独立于语言,平台
  5. 具有自我描述性

四. Gson 是什么?

​ Google Gson是一个简单的基于Java的库,用于将Java对象序列化为JSON,反之亦然。 它是由Google开发的开源库。

说白了就是专门为了方便解析Json而设计的一个开源库。

​ 以下几点强调了您应该使用此库的原因 :

  • Standardized - Gson是由Google管理的标准化库。
  • Efficient - 它是Java标准库的可靠,快速和高效的扩展。
  • Optimized - 库高度优化。
  • Support Generics - 它为泛型提供广泛的支持。
  • Supports complex inner classes - 它支持具有深层继承层次结构的复杂对象。

五. Gson的特点

以下列出了Gson的一些最突出的功能

  • Easy to use - Gson API提供了一个高级外观,以简化常用的用例。
  • No need to create mapping - Gson API为大多数要序列化的对象提供默认映射。
  • Performance - Gson速度非常快,内存占用少。 它适用于大型对象图或系统。
  • Clean JSON - Gson创建一个干净,紧凑的JSON结果,易于阅读。
  • No Dependency - 除了JDK之外,Gson库不需要任何其他库。
  • Open Source - Gson库是开源的; 它是免费提供的

六. Gson 的基本使用

6.1 Gson 创建实例的两种方式

6.1.1 new Gson()
这种方式如6.1 章节所示,没什么好说的,直接 Gson gson = new Gson(),就可以了
    我们这章先讲解用法,暂时不讲解原理
6.1.2 new GsonBuilder()
GsonBuilder gsonBuilder = new GsonBuilder();
 // 使用构建者模式来创建一个复杂对象。
 // 可以根据需要进行配置,常用的也就注释中的那几个,其他的可以根绝需要再查询使用

        GsonBuilder gsonBuilder = new GsonBuilder();                 
        gsonBuilder.setPrettyPrinting()                          // 设置格式打印;
                .registerTypeAdapter()                           // 设置TypeAdapter
                .excludeFieldsWithoutExposeAnnotation()
                .addDeserializationExclusionStrategy()
                .addSerializationExclusionStrategy()
                .disableHtmlEscaping()
                .enableComplexMapKeySerialization()
                .disableInnerClassSerialization()
                .excludeFieldsWithModifiers()
                .generateNonExecutableJson()
                .registerTypeAdapterFactory()
                .registerTypeHierarchyAdapter()
                .setDateFormat()
                .serializeNulls()                               // 提供在Json输出中显示NULL值的标志
                .serializeSpecialFloatingPointValues()
                .setExclusionStrategies()
                .setLenient()
                .setVersion()                                   // 设置版本号,用于版本控制
                .setLongSerializationPolicy()
                .setFieldNamingPolicy()
                .setFieldNamingStrategy();
        Gson gsonx = gsonBuilder.create();                      // 通过create()方法创建一个Gson对象

6.1.3 选择哪种方式来创建Gson实例
  1. 简单使用的情况使用new Gson()

  2. 需要自定义TypeAdapter的,设置格式输出的,总之就是你需要自定义一些配置的,选择new GsonBuilder()的方式

6.2 如何通过Gson对对象进行序列化和反序列化

6.2.1 使用Gson对java bean对象进行序列化

IDE:Android Studio

  1. 创建一个简单的工程

  2. 在Gradle中添加 implementation ‘com.google.code.gson:gson:2.8.4’

  3. 创建两个java bean类

  4. 创建 Gson实例,通过toJson 和fromJson方法来进行对象的序列化和反序列化操作

    示例代码如下:

// Java bean类
public class Course {
    private String name;
    private float score;

    public Course() {
        System.out.println("_Course: empty");
    }


    public Course(String name, float score) {
        this.name = name;
        this.score = score;
    }


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public float getScore() {
        return score;
    }

    public void setScore(float score) {
        this.score = score;
    }


    @Override
    public String toString() {
        return "Course{" +
                "name='" + name + '\'' +
                ", score=" + score +
                '}';
    }
}

// java bean类
public class Student {
    private int id;
    private String name;
    private String sax;
    private Integer age;
    private List<Course> courses;

    public Student() {
        courses = new ArrayList<>();
    }

    public Student(int id, String name, String sax, Integer age) {
        this.id = id;
        this.name = name;
        this.sax = sax;
        this.age = age;
        courses = new ArrayList<>();
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSax() {
        return sax;
    }

    public void setSax(String sax) {
        this.sax = sax;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public List<Course> getCourses() {
        return courses;
    }

    public void setCourses(List<Course> courses) {
        this.courses = courses;
    }

    public void addCourse(Course course) {
        this.courses.add(course);
    }

    public void addAllCourses(List<Course> courses) {
        this.courses.addAll(courses);
    }


    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", sax='" + sax + '\'' +
                ", age=" + age +
                ", courses=" + courses +
                '}';
    }
}

// MainActivity
public class MainActivity extends AppCompatActivity {
     @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // 1. 创建一个待序列化的Student的实例
        // 2. 设置属性值
        // 3. 序列化/反序列化
        
        // 创建实例
        Student student = new Student();
        // 设置属性值
        student.setId(1);
        student.setName("test");
        student.setAge(18);
        student.setSax("nan");
        Course course = new Course();
        course.setName("英语");
        course.setScore(89);
        student.addCourse(course);
        course.setName("数学");
        course.setScore(100);
        student.addCourse(course);
        course.setName("语文");
        course.setScore(115);
        student.addCourse(course);
        // 创建Gson实例:这是一种创建方式,后面我们再讲解其他的方式怎么用
        Gson gson = new Gson();
        // 调用toJson方法将对象序列化为Json字符串
        String tojson = gson.toJson(student);
        // 打印
        System.out.println(tojson);
       // I/System.out: {"age":18,"courses":[{"name":"语文","score":115.0},{"name":"语文","score":115.0},{"name":"语文","score":115.0}],"id":1,"name":"test","sax":"nan"}
        
        
        // 反序列化: 第一个参数传入json字符串,第二个参数传入反序列化的 类
        Student student1 = gson.fromJson(tojson, Student.class);
        // 打印
        System.out.println(student1);
        // I/System.out: Student{id=1, name='test', sax='nan', age=18, courses=[Course{name='语文', score=115.0}, Course{name='语文', score=115.0}, Course{name='语文', score=115.0}]}
    }
}




6.2.2 使用Gson对基本类型的数据进行序列化

Gson 不仅仅是能序列化对象类型,其他基本类型的同样可以,代码如下:

        // 创建对象
        Gson gson = new Gson();
        // 单个数字
        System.out.println(gson.toJson(1));  // 1
        // 单个字符串
        System.out.println(gson.toJson("jiangc"));    // "jiangc"
        // 数组
        int[] values = {1, 2, 3};
        System.out.println(gson.toJson(values));      // [1,2,3]

        int i = gson.fromJson("1", int.class);        
        System.out.println(i);                       // 1
6.2.3 使用自定义TypeAdapter 对Java bean对象进行序列化和反序列化
  1. 通过扩展TypeAdapter类并将其传递给目标对象的类型来创建自定义适配器。 重写readwrite方法以分别执行自定义反序列化和序列化。
class StudentAdapter extends TypeAdapter<Student> { 
   @Override 
   public Student read(JsonReader reader) throws IOException { 
      ... 
   } 
   @Override 
   public void write(JsonWriter writer, Student student) throws IOException { 
   } 
}
  1. 实际使用例子如下:
/**
 * Gson使用    Java bean 类,这个例子中大家先不要关注注解,那是用来版本控制用的,这里暂时不用
 */
public class UseGson {
    @SerializedName("ID")              // 这个注解是在序列化后将 id -> ID
    @Expose
    @Until(2.0) private int id;        // @Until(版本号) 用于版本控制,当版本号 <= 2.0的时候才会参与序列化和反序列化  ,版本号通过GsonBuilder.setVersion()来设置
    @SerializedName("NAME")
    @Expose
    @Until(2.0) private String name;

    // TODO: 注意,使用Expose注解需要使用  GsonBuilder() 来构造Gson  不能使用Gson()构造了,否则无用, 另外如果使用GsonBUilder() 那么需要序列化的字段都需要手动添加@Expose注解
    @Expose(serialize = true, deserialize = true)                            // 序列化/反序列化标示,默认都为true, 可以手动设置打开/关闭  序列化/反序列化
    @Since(1.0) private String age;                         // @Since(版本号) 用于版本控制 当版本号 >= 1.0时才会被序列化
    @Expose(serialize = false, deserialize = false)    // 这里标志不参与序列化,也不参与反序列化
    @Since(1.0) private String sax = null;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


    public String getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "UseGson{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age='" + age + '\'' +
                ", sax='" + sax + '\'' +
                '}';
    }

    public void setAge(String age) {
        this.age = age;
    }


    public String getSax() {
        return sax;
    }

    public void setSax(String sax) {
        this.sax = sax;
    }
}

/**
 * 扩展自 TypeAdapter的自定义Adapter
 */
public class UseGsonAdapter extends TypeAdapter<UseGson> {
    /**
     * 序列化
     * @param out
     * @param value
     * @throws IOException
     */
    @Override
    public void write(JsonWriter out, UseGson value) throws IOException {

        out.beginObject();           // 这里是Object的开始 其实是写了一个 '{'
        out.name("name");            // 写入key
        out.value(value.getName());  // 写入value
        out.name("id");
        out.value(value.getId());
        out.name("age");
        out.value(value.getAge());
        out.name("sax");
        out.value(value.getSax());
        out.endObject();              // 这里是Object的结束  其实是写了一个 '}'
    }

    /**
     * 反序列化
     * @param in
     * @return
     * @throws IOException
     */
    @Override
    public UseGson read(JsonReader in) throws IOException {
        UseGson student = new UseGson();
        in.beginObject();
        String fieldname = null;
        while (in.hasNext()) {
            // 这个和序列化的操作相反,根据读取字段的值来一一设置属性的值
            JsonToken token = in.peek();           // 获取下一个令牌的类型
            if (token.equals(JsonToken.NAME)) {
                // 获取当前token的值
                fieldname = in.nextName();
            }

            if ("name".equals(fieldname)) {
                // 移动到下一个令牌
                token = in.peek();
                student.setName(in.nextString());
            }

            if ("id".equals(fieldname)) {
                // 移动到下一个令牌
                token = in.peek();
                student.setId(in.nextInt());
            }

            if ("age".equals(fieldname)) {
                // 移动到下一个令牌
                token = in.peek();
                student.setAge(in.nextString());
            }
            if ("sax".equals(fieldname)) {
                // 移动到下一个令牌
                token = in.peek();
                student.setSax(in.nextString());
            }
        }
        in.endObject();
        return student;
    }
}


// MainActivity
public class MainActivity extends AppCompatActivity {
     @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 性能提高以及容错处理
        GsonBuilder builder = new GsonBuilder();
        // 使用 registerTypeAdapter 来注册我们自己的TypeAdapter
        builder.registerTypeAdapter(UseGson.class, new UseGsonAdapter());
        builder.setPrettyPrinting();
        Gson builderGson = builder.create();

        // 序列化
        UseGson useGson = new UseGson();
        useGson.setId(1);
        useGson.setSax("nan");
        useGson.setAge("18");
        useGson.setName("jiangc");

        String strJson = builderGson.toJson(useGson);
        System.out.println("typeAdapter: " + strJson);
        // 反序列化
        System.out.println(builderGson.fromJson(strJson, UseGson.class));
        
    }
}
6.2.4 实现 JsonSerializer和JsonDeserializer 接口自定义序列化和反序列化
  1. 首先看一下如何使用
/**
 * 实现JsonDeserializer 接口进行自定义反序列化
 * 实现JsonSerializer 接口进行自定义序列化
 */
public class GsonImplementJsonDeserializer implements JsonDeserializer<Course>, JsonSerializer<Course> {
    @Override
    public Course deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        return null;
    }

    @Override
    public JsonElement serialize(Course src, Type typeOfSrc, JsonSerializationContext context) {
        return null;
    }
}
  1. 在使用之前我们先来了解一下JsonElement 这个类

    ​ 首先,这个类是一个抽象类,代表着Json字符串中的某一个元素。这个元素可以是一个对象(Object)、可以是一个数组(JsonArray)、可以是一个Java的基本类型(JsonPrimitive)、当然也可以是null(JsonNull);JsonObject,JsonArray, JsonPrimitive,JsonNull都是JsonElement这个抽象类的子类。JsonElement提供了一系列的方法来判断当前的JsonElement各个JsonElement的关系

    各个JsonElement的关系可以用如下图标识:

    Gson 使用篇

    也可以用类图:

    Gson 使用篇

    JsonObject对象可以看成 key/value的集合,而这些values就是一个个JsonElement,他们的结构可以用如下图表示:

    Gson 使用篇

    JsonElement的代码如下:

public abstract class JsonElement {

    /**
    * 唯一一个抽象方法,子类必须实现的,用来递归获取JsonElement中的子元素以及子元素的子元素
    */
  public abstract JsonElement deepCopy();

  /**
   * 判断当前元素是否是数组,如果是返回true
   */
  public boolean isJsonArray() {
    return this instanceof JsonArray;
  }

  /**
   * 判断当前元素是否是Object,如果是返回true
   */
  public boolean isJsonObject() {
    return this instanceof JsonObject;
  }

  /**
   * 判断当前元素是否是Primitive,如果是返回true
   */
  public boolean isJsonPrimitive() {
    return this instanceof JsonPrimitive;
  }

  /**
   * 判断当前元素是否是Null,如果是返回true
   */
  public boolean isJsonNull() {
    return this instanceof JsonNull;
  }

  /**
   * 以JsonObject的形式获取该元素的方法,如果元素是某个元素的其他类型,则抛出IllegalStateException
   * 如果是JsonObject类型的则强转为JsonObject返回JsonObject
   */
  public JsonObject getAsJsonObject() {
    if (isJsonObject()) {
      return (JsonObject) this;
    }
    throw new IllegalStateException("Not a JSON Object: " + this);
  }

  /**
   * 以JsonArray的形式获取该元素的方法,如果元素是某个元素的其他类型,则抛出IllegalStateException
   * 如果是JsonArray类型的则强转为JsonArray返回JsonArray
   */
  public JsonArray getAsJsonArray() {
    if (isJsonArray()) {
      return (JsonArray) this;
    }
    throw new IllegalStateException("Not a JSON Array: " + this);
  }

  /**
   * 以JsonPrimitive的形式获取该元素的方法,如果元素是某个元素的其他类型,则抛出IllegalStateException
   * 如果是JsonPrimitive类型的则强转为JsonPrimitive返回JsonPrimitive
   */
  public JsonPrimitive getAsJsonPrimitive() {
    if (isJsonPrimitive()) {
      return (JsonPrimitive) this;
    }
    throw new IllegalStateException("Not a JSON Primitive: " + this);
  }

  /**
   * 以JsonNull的形式获取该元素的方法,如果元素是某个元素的其他类型,则抛出IllegalStateException
   * 如果是JsonNull类型的则强转为JsonNull返回JsonNull
   */
  public JsonNull getAsJsonNull() {
    if (isJsonNull()) {
      return (JsonNull) this;
    }
    throw new IllegalStateException("Not a JSON Null: " + this);
  }

  /**
   * 这个方法主要是用来获取一个boolean的值,这里直接抛出一个异常是因为这个方法是让子类来重写的,如果你不重写就调用就会出现异常
   */
  public boolean getAsBoolean() {
    throw new UnsupportedOperationException(getClass().getSimpleName());
  }

  /**
   * 这个方法主要是用来获取一个BooleanWrapper的值,这里直接抛出一个异常是因为这个方法是让子类来重写的,如果你不重写就调用就会出现异常
   */
  Boolean getAsBooleanWrapper() {
    throw new UnsupportedOperationException(getClass().getSimpleName());
  }

  /**
   * 这个方法主要是用来获取一个Number的值,这里直接抛出一个异常是因为这个方法是让子类来重写的,如果你不重写就调用就会出现异常
   */
  public Number getAsNumber() {
    throw new UnsupportedOperationException(getClass().getSimpleName());
  }

  /**
   * 这个方法主要是用来获取一个String的值,这里直接抛出一个异常是因为这个方法是让子类来重写的,如果你不重写就调用就会出现异常
   */
  public String getAsString() {
    throw new UnsupportedOperationException(getClass().getSimpleName());
  }

  /**
   * 这个方法主要是用来获取一个Double的值,这里直接抛出一个异常是因为这个方法是让子类来重写的,如果你不重写就调用就会出现异常
   */
  public double getAsDouble() {
    throw new UnsupportedOperationException(getClass().getSimpleName());
  }

  /**
   * 这个方法主要是用来获取一个Float的值,这里直接抛出一个异常是因为这个方法是让子类来重写的,如果你不重写就调用就会出现异常
   */
  public float getAsFloat() {
    throw new UnsupportedOperationException(getClass().getSimpleName());
  }

  /**
   * 这个方法主要是用来获取一个Long的值,这里直接抛出一个异常是因为这个方法是让子类来重写的,如果你不重写就调用就会出现异常
   */
  public long getAsLong() {
    throw new UnsupportedOperationException(getClass().getSimpleName());
  }

  /**
   * 这个方法主要是用来获取一个Int的值,这里直接抛出一个异常是因为这个方法是让子类来重写的,如果你不重写就调用就会出现异常
   */
  public int getAsInt() {
    throw new UnsupportedOperationException(getClass().getSimpleName());
  }

  /**
   * 这个方法主要是用来获取一个Byte的值,这里直接抛出一个异常是因为这个方法是让子类来重写的,如果你不重写就调用就会出现异常
   */
  public byte getAsByte() {
    throw new UnsupportedOperationException(getClass().getSimpleName());
  }

  /**
   * 这个方法主要是用来获取一个Character的值,这里直接抛出一个异常是因为这个方法是让子类来重写的,如果你不重写就调用就会出现异常
   */
  public char getAsCharacter() {
    throw new UnsupportedOperationException(getClass().getSimpleName());
  }

  /**
   * 这个方法主要是用来获取一个BigDecimal的值,这里直接抛出一个异常是因为这个方法是让子类来重写的,如果你不重写就调用就会出现异常
   */
  public BigDecimal getAsBigDecimal() {
    throw new UnsupportedOperationException(getClass().getSimpleName());
  }

  /**
   * 这个方法主要是用来获取一个BigInteger的值,这里直接抛出一个异常是因为这个方法是让子类来重写的,如果你不重写就调用就会出现异常
   */
  public BigInteger getAsBigInteger() {
    throw new UnsupportedOperationException(getClass().getSimpleName());
  }

  /**
   * 这个方法主要是用来获取一个Short的值,这里直接抛出一个异常是因为这个方法是让子类来重写的,如果你不重写就调用就会出现异常
   */
  public short getAsShort() {
    throw new UnsupportedOperationException(getClass().getSimpleName());
  }

  /**
   * Returns a String representation of this element.
   */
  @Override
  public String toString() {
    try {
      StringWriter stringWriter = new StringWriter();
      JsonWriter jsonWriter = new JsonWriter(stringWriter);
      jsonWriter.setLenient(true);
      Streams.write(this, jsonWriter);
      return stringWriter.toString();
    } catch (IOException e) {
      throw new AssertionError(e);
    }
  }
}

这个类中的方法分为4类:

  1. 判断JsonElement的类型

  2. 获取指定类型的JsonElement

  3. 获取基本类型的值

  4. 获取基本类型的包装类的值

    上面都有注释,大家可以看一下,具体有什么用,我们继续往下看

那么问题来了,这个东西用来表示不同类型的JsonElement,它有什么用处呢?从上面的图我们可以看出,它

总共有4个子类,分别是 JsonArray、JsonNull、JsonObject、JsonPrimitive,我们先看一下都实现了什么方法

6.4.2.1 JsonArray
public final class JsonArray extends JsonElement implements Iterable<JsonElement> {
  private final List<JsonElement> elements;

  /**
   * 无参构造方法
   */
  public JsonArray() {
    elements = new ArrayList<JsonElement>();
  }
  /**
  * 指定容量的有参构造方法
  */
  public JsonArray(int capacity) {
    elements = new ArrayList<JsonElement>(capacity);
  }

  /**
   * 创建该元素及其所有子元素的副本,添加到数组中返回
   * @since 2.8.2
   */
  @Override
  public JsonArray deepCopy() {
    if (!elements.isEmpty()) {
      JsonArray result = new JsonArray(elements.size());
      for (JsonElement element : elements) {
        result.add(element.deepCopy());
      }
      return result;
    }
    return new JsonArray();
  }

  /**
   * 将指定的bool值添加到数组中
   */
  public void add(Boolean bool) {
    elements.add(bool == null ? JsonNull.INSTANCE : new JsonPrimitive(bool));
  }

  /**
   * 将指定的character值添加到数组中
   */
  public void add(Character character) {
    elements.add(character == null ? JsonNull.INSTANCE : new JsonPrimitive(character));
  }

  /**
   * 将指定的number值添加到数组中
   */
  public void add(Number number) {
    elements.add(number == null ? JsonNull.INSTANCE : new JsonPrimitive(number));
  }

  /**
   * 将指定的String值添加到数组中
   */
  public void add(String string) {
    elements.add(string == null ? JsonNull.INSTANCE : new JsonPrimitive(string));
  }

  /**
   * 将指定的JsonElement值添加到数组中
   */
  public void add(JsonElement element) {
    if (element == null) {
      element = JsonNull.INSTANCE;
    }
    elements.add(element);
  }

  /**
   * 将指定的JsonArray值添加到数组中
   */
  public void addAll(JsonArray array) {
    elements.addAll(array.elements);
  }

  /**
   * 将数组中指定位置的元素替换为指定元素
   * @param index 要替换的元素索引
   * @param element 被用来替换指定索引位置的元素
   * @return JsonElement 返回之前指定位置的元素
   * @throws 如果指定的索引超出数组边界,则抛出 IndexOutOfBoundsException
   */
  public JsonElement set(int index, JsonElement element) {
    return elements.set(index, element);
  }

  /**
   * 从该数组中删除第一个出现的指定元素(如果它存在的话)
   * 如果数组中不包含该元素,则数组不变
   * @param element 要从数组中移除的元素(如果存在)
   * @return 如果该数组包含指定的元素,则返回true,否则返回false
   * @since 2.3
   */
  public boolean remove(JsonElement element) {
    return elements.remove(element);
  }

  /**
   * 移除数组中指定位置的元素.将后面的元素向前移一个位置,返回已经删除的元素
   * @param index 要删除的元素的索引
   * @return 返回之前指定位置的元素
   * @throws 如果指定的索引超出数组边界,则抛出IndexOutOfBoundsException异常
   * @since 2.3
   */
  public JsonElement remove(int index) {
    return elements.remove(index);
  }

  /**
   * 如果数组中包含整个element则返回true,否则返回false
   * @return true if this array contains the specified element.
   * @param element whose presence in this array is to be tested
   * @since 2.3
   */
  public boolean contains(JsonElement element) {
    return elements.contains(element);
  }

  /**
   * 返回数组中元素的数量
   *
   * @return the number of elements in the array.
   */
  public int size() {
    return elements.size();
  }

  /**
   * 返回一个遍历数组元素的迭代器,由于数组是有序列表,迭代器按照插入元素的顺序进行迭代
   *
   * @return an iterator to navigate the elements of the array.
   */
  public Iterator<JsonElement> iterator() {
    return elements.iterator();
  }

  /**
   * 返回数组的第i个元素
   *
   * @param i 要查找的元素的索引
   * @return 返回第i个索引的元素
   * @throws IndexOutOfBoundsException if i is negative or greater than or equal to the
   * {@link #size()} of the array.
   */
  public JsonElement get(int i) {
    return elements.get(i);
  }

  /**
   * 如果该数组包含单个元素,则以Number的形式获取该数组的方便方法
   *
   * @return 如果是单元素数组,则将该元素作为一个数字获取
   * @throws 如果数组中不是JsonPrimitive和有效数字则抛出ClassCastExcption
   * @throws 如果数组有一个以上的元素,则抛出IIIegalStateException
   */
  @Override
  public Number getAsNumber() {
    if (elements.size() == 1) {
      return elements.get(0).getAsNumber();
    }
    throw new IllegalStateException();
  }

  /**
   * 如果该数组包含单个元素,则以String的形式获取该数组的方便方法
   *
   * @return 如果是单元素数组,则将该元素作为一个字符串获取
   * @throws 如果数组中不是JsonPrimitive和有效字符串则抛出ClassCastExcption
   * @throws 如果数组有一个以上的元素,则抛出IIIegalStateException
   */
  @Override
  public String getAsString() {
    if (elements.size() == 1) {
      return elements.get(0).getAsString();
    }
    throw new IllegalStateException();
  }

   /**
   * 如果该数组包含单个元素,则以Double的形式获取该数组的方便方法
   *
   * @return 如果是单元素数组,则将该元素作为一个double获取
   * @throws 如果数组中不是JsonPrimitive和有效double则抛出ClassCastExcption
   * @throws 如果数组有一个以上的元素,则抛出IIIegalStateException
   */
  @Override
  public double getAsDouble() {
    if (elements.size() == 1) {
      return elements.get(0).getAsDouble();
    }
    throw new IllegalStateException();
  }

  /**
   * 如果该数组包含单个元素,则以BigDecimal的形式获取该数组的方便方法
   *
   * @return 如果是单元素数组,则将该元素作为一个BigDecimal获取
   * @throws 如果数组中不是JsonPrimitive和有效BigDecimal则抛出ClassCastExcption
   * @throws 如果数组有一个以上的元素,则抛出IIIegalStateException
   */
  @Override
  public BigDecimal getAsBigDecimal() {
    if (elements.size() == 1) {
      return elements.get(0).getAsBigDecimal();
    }
    throw new IllegalStateException();
  }

 /**
   * 如果该数组包含单个元素,则以BigInteger的形式获取该数组的方便方法
   *
   * @return 如果是单元素数组,则将该元素作为一个BigInteger获取
   * @throws 如果数组中不是JsonPrimitive和有效BigInteger则抛出ClassCastExcption
   * @throws 如果数组有一个以上的元素,则抛出IIIegalStateException
   */
  @Override
  public BigInteger getAsBigInteger() {
    if (elements.size() == 1) {
      return elements.get(0).getAsBigInteger();
    }
    throw new IllegalStateException();
  }

 /**
   * 如果该数组包含单个元素,则以Float的形式获取该数组的方便方法
   *
   * @return 如果是单元素数组,则将该元素作为一个Float获取
   * @throws 如果数组中不是JsonPrimitive和有效Float则抛出ClassCastExcption
   * @throws 如果数组有一个以上的元素,则抛出IIIegalStateException
   */
  @Override
  public float getAsFloat() {
    if (elements.size() == 1) {
      return elements.get(0).getAsFloat();
    }
    throw new IllegalStateException();
  }

 /**
   * 如果该数组包含单个元素,则以Long的形式获取该数组的方便方法
   *
   * @return 如果是单元素数组,则将该元素作为一个Long获取
   * @throws 如果数组中不是JsonPrimitive和有效Long则抛出ClassCastExcption
   * @throws 如果数组有一个以上的元素,则抛出IIIegalStateException
   */
  @Override
  public long getAsLong() {
    if (elements.size() == 1) {
      return elements.get(0).getAsLong();
    }
    throw new IllegalStateException();
  }

 /**
   * 如果该数组包含单个元素,则以Int的形式获取该数组的方便方法
   *
   * @return 如果是单元素数组,则将该元素作为一个Int获取
   * @throws 如果数组中不是JsonPrimitive和有效Int则抛出ClassCastExcption
   * @throws 如果数组有一个以上的元素,则抛出IIIegalStateException
   */
  @Override
  public int getAsInt() {
    if (elements.size() == 1) {
      return elements.get(0).getAsInt();
    }
    throw new IllegalStateException();
  }

    /**
    * 同上
    */
  @Override
  public byte getAsByte() {
    if (elements.size() == 1) {
      return elements.get(0).getAsByte();
    }
    throw new IllegalStateException();
  }

    /**
    *  同上
    */
  @Override
  public char getAsCharacter() {
    if (elements.size() == 1) {
      return elements.get(0).getAsCharacter();
    }
    throw new IllegalStateException();
  }

  /**
   * 同上
   */
  @Override
  public short getAsShort() {
    if (elements.size() == 1) {
      return elements.get(0).getAsShort();
    }
    throw new IllegalStateException();
  }

  /**
   * 同上
   */
  @Override
  public boolean getAsBoolean() {
    if (elements.size() == 1) {
      return elements.get(0).getAsBoolean();
    }
    throw new IllegalStateException();
  }

  @Override
  public boolean equals(Object o) {
    return (o == this) || (o instanceof JsonArray && ((JsonArray) o).elements.equals(elements));
  }

  @Override
  public int hashCode() {
    return elements.hashCode();
  }
}
6.4.2.2 JsonPrimitive
public final class JsonPrimitive extends JsonElement {

    // 定义了一个类型数组,包含了所有的基本类型
  private static final Class<?>[] PRIMITIVE_TYPES = { int.class, long.class, short.class,
      float.class, double.class, byte.class, boolean.class, char.class, Integer.class, Long.class,
      Short.class, Float.class, Double.class, Byte.class, Boolean.class, Character.class };

  private Object value;

    
    // 下面都是不同类型的构造方法
  /**
   * Create a primitive containing a boolean value.
   *
   * @param bool the value to create the primitive with.
   */
  public JsonPrimitive(Boolean bool) {
    setValue(bool);
  }

  /**
   * Create a primitive containing a {@link Number}.
   *
   * @param number the value to create the primitive with.
   */
  public JsonPrimitive(Number number) {
    setValue(number);
  }

  /**
   * Create a primitive containing a String value.
   *
   * @param string the value to create the primitive with.
   */
  public JsonPrimitive(String string) {
    setValue(string);
  }

  /**
   * Create a primitive containing a character. The character is turned into a one character String
   * since Json only supports String.
   *
   * @param c the value to create the primitive with.
   */
  public JsonPrimitive(Character c) {
    setValue(c);
  }

  /**
   * Create a primitive using the specified Object. It must be an instance of {@link Number}, a
   * Java primitive type, or a String.
   *
   * @param primitive the value to create the primitive with.
   */
  JsonPrimitive(Object primitive) {
    setValue(primitive);
  }

  /**
   * Returns the same value as primitives are immutable.
   * 还记的上面的那张图吗?,JsonPrimitive类似于一颗树的叶子节点,它没有子节点,所以直接返回自己
   * @since 2.8.2
   */
  @Override
  public JsonPrimitive deepCopy() {
    return this;
  }

    /**
    * 设置 primitive的值
    */
  void setValue(Object primitive) {
    if (primitive instanceof Character) {
      // 将字符转换为字符串,因为在JSON中,字符表示单个字符串
      char c = ((Character) primitive).charValue();
      this.value = String.valueOf(c);
    } else {
      $Gson$Preconditions.checkArgument(primitive instanceof Number
              || isPrimitiveOrString(primitive));
      this.value = primitive;
    }
  }

  /**
   * 判断是否是boolean 类型,是的话返回true,否则返回false ,下面所有isxxx()的都是判断类型的
   */
  public boolean isBoolean() {
    return value instanceof Boolean;
  }

  /**
   *以boolean的形式获取该元素,将value强转为boolean类型,下面所有getAsXXX()都是获取xxx类型的数据的
   */
  @Override
  Boolean getAsBooleanWrapper() {
    return (Boolean) value;
  }

  /**
   * convenience method to get this element as a boolean value.
   *
   * @return get this element as a primitive boolean value.
   */
  @Override
  public boolean getAsBoolean() {
    if (isBoolean()) {
      return getAsBooleanWrapper().booleanValue();
    } else {
      // Check to see if the value as a String is "true" in any case.
      return Boolean.parseBoolean(getAsString());
    }
  }

  /**
   * Check whether this primitive contains a Number.
   *
   * @return true if this primitive contains a Number, false otherwise.
   */
  public boolean isNumber() {
    return value instanceof Number;
  }

  /**
   * convenience method to get this element as a Number.
   *
   * @return get this element as a Number.
   * @throws NumberFormatException if the value contained is not a valid Number.
   */
  @Override
  public Number getAsNumber() {
    return value instanceof String ? new LazilyParsedNumber((String) value) : (Number) value;
  }

  /**
   * Check whether this primitive contains a String value.
   *
   * @return true if this primitive contains a String value, false otherwise.
   */
  public boolean isString() {
    return value instanceof String;
  }

  /**
   * convenience method to get this element as a String.
   *
   * @return get this element as a String.
   */
  @Override
  public String getAsString() {
    if (isNumber()) {
      return getAsNumber().toString();
    } else if (isBoolean()) {
      return getAsBooleanWrapper().toString();
    } else {
      return (String) value;
    }
  }

  /**
   * convenience method to get this element as a primitive double.
   *
   * @return get this element as a primitive double.
   * @throws NumberFormatException if the value contained is not a valid double.
   */
  @Override
  public double getAsDouble() {
    return isNumber() ? getAsNumber().doubleValue() : Double.parseDouble(getAsString());
  }

  /**
   * convenience method to get this element as a {@link BigDecimal}.
   *
   * @return get this element as a {@link BigDecimal}.
   * @throws NumberFormatException if the value contained is not a valid {@link BigDecimal}.
   */
  @Override
  public BigDecimal getAsBigDecimal() {
    return value instanceof BigDecimal ? (BigDecimal) value : new BigDecimal(value.toString());
  }

  /**
   * convenience method to get this element as a {@link BigInteger}.
   *
   * @return get this element as a {@link BigInteger}.
   * @throws NumberFormatException if the value contained is not a valid {@link BigInteger}.
   */
  @Override
  public BigInteger getAsBigInteger() {
    return value instanceof BigInteger ?
        (BigInteger) value : new BigInteger(value.toString());
  }

  /**
   * convenience method to get this element as a float.
   *
   * @return get this element as a float.
   * @throws NumberFormatException if the value contained is not a valid float.
   */
  @Override
  public float getAsFloat() {
    return isNumber() ? getAsNumber().floatValue() : Float.parseFloat(getAsString());
  }

  /**
   * convenience method to get this element as a primitive long.
   *
   * @return get this element as a primitive long.
   * @throws NumberFormatException if the value contained is not a valid long.
   */
  @Override
  public long getAsLong() {
    return isNumber() ? getAsNumber().longValue() : Long.parseLong(getAsString());
  }

  /**
   * convenience method to get this element as a primitive short.
   *
   * @return get this element as a primitive short.
   * @throws NumberFormatException if the value contained is not a valid short value.
   */
  @Override
  public short getAsShort() {
    return isNumber() ? getAsNumber().shortValue() : Short.parseShort(getAsString());
  }

 /**
  * convenience method to get this element as a primitive integer.
  *
  * @return get this element as a primitive integer.
  * @throws NumberFormatException if the value contained is not a valid integer.
  */
  @Override
  public int getAsInt() {
    return isNumber() ? getAsNumber().intValue() : Integer.parseInt(getAsString());
  }

  @Override
  public byte getAsByte() {
    return isNumber() ? getAsNumber().byteValue() : Byte.parseByte(getAsString());
  }

  @Override
  public char getAsCharacter() {
    return getAsString().charAt(0);
  }

  private static boolean isPrimitiveOrString(Object target) {
    if (target instanceof String) {
      return true;
    }

    Class<?> classOfPrimitive = target.getClass();
    for (Class<?> standardPrimitive : PRIMITIVE_TYPES) {
      if (standardPrimitive.isAssignableFrom(classOfPrimitive)) {
        return true;
      }
    }
    return false;
  }

  @Override
  public int hashCode() {
    if (value == null) {
      return 31;
    }
    // Using recommended hashing algorithm from Effective Java for longs and doubles
    if (isIntegral(this)) {
      long value = getAsNumber().longValue();
      return (int) (value ^ (value >>> 32));
    }
    if (value instanceof Number) {
      long value = Double.doubleToLongBits(getAsNumber().doubleValue());
      return (int) (value ^ (value >>> 32));
    }
    return value.hashCode();
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (obj == null || getClass() != obj.getClass()) {
      return false;
    }
    JsonPrimitive other = (JsonPrimitive)obj;
    if (value == null) {
      return other.value == null;
    }
    if (isIntegral(this) && isIntegral(other)) {
      return getAsNumber().longValue() == other.getAsNumber().longValue();
    }
    if (value instanceof Number && other.value instanceof Number) {
      double a = getAsNumber().doubleValue();
      // Java standard types other than double return true for two NaN. So, need
      // special handling for double.
      double b = other.getAsNumber().doubleValue();
      return a == b || (Double.isNaN(a) && Double.isNaN(b));
    }
    return value.equals(other.value);
  }

  /**
   * Returns true if the specified number is an integral type
   * (Long, Integer, Short, Byte, BigInteger)
   */
  private static boolean isIntegral(JsonPrimitive primitive) {
    if (primitive.value instanceof Number) {
      Number number = (Number) primitive.value;
      return number instanceof BigInteger || number instanceof Long || number instanceof Integer
          || number instanceof Short || number instanceof Byte;
    }
    return false;
  }
}
6.4.2.3 JsonObject
public final class JsonObject extends JsonElement {

    // 这里用的是一个LinkTreeMap ,其中存储的是以String为Key ,JsonElement为值的树
    private final LinkedTreeMap<String, JsonElement> members =
      new LinkedTreeMap<String, JsonElement>();

  /**
   * 创建该元素及其所有子元素的深层副本
   * @since 2.8.2
   */
  @Override
  public JsonObject deepCopy() {
    JsonObject result = new JsonObject();
    for (Map.Entry<String, JsonElement> entry : members.entrySet()) {
      result.add(entry.getKey(), entry.getValue().deepCopy());
    }
    return result;
  }

  /**
   * 将成员(键-值对)添加到members,名称必须为字符串,值可以是任意的JsonElement,从而允许狗键完整的JsonElement树根在这个节点上
   * @param 成员的属性名
   * @param 成员的值
   */
  public void add(String property, JsonElement value) {
    if (value == null) {
      value = JsonNull.INSTANCE;
    }
    members.put(property, value);
  }

  /**
   * 从这个树中删除指定名称的JsonElement
   *
   * @param 指定被移除的成员的属性名
   * @return 被移除的JsonElement对象
   * @since 1.3
   */
  public JsonElement remove(String property) {
    return members.remove(property);
  }

  /**
   * 添加值为基本类型String的JsonElement
   *
   * @param 属性名
   * @param 属性的值,字符串类型
   */
  public void addProperty(String property, String value) {
    add(property, createJsonElement(value));
  }

/**
   * 添加值为基本类型Number的JsonElement
   *
   * @param 属性名
   * @param 属性的值 Number类型
   */
  public void addProperty(String property, Number value) {
    add(property, createJsonElement(value));
  }

/**
   * 添加值为基本类型Boolean的JsonElement
   *
   * @param 属性名
   * @param 属性的值 Boolean类型
   */
  public void addProperty(String property, Boolean value) {
    add(property, createJsonElement(value));
  }

/**
   * 添加值为基本类型Character的JsonElement
   *
   * @param 属性名
   * @param 属性的值 Character类型
   */
  public void addProperty(String property, Character value) {
    add(property, createJsonElement(value));
  }

  /**
   * 从给定的value来创建JsonElement.
   *
   * @param 要生成的JsonElement对象
   * @return 如果value不为null返回JsonPrimitive ,否则返回JsonNull
   */
  private JsonElement createJsonElement(Object value) {
    return value == null ? JsonNull.INSTANCE : new JsonPrimitive(value);
  }

  /**
   * 返回此对象的一组成员,集合是有序的,顺序是添加元素的顺序
   *
   * @return 返回该对象的一组成员
   */
  public Set<Map.Entry<String, JsonElement>> entrySet() {
    return members.entrySet();
  }

  /**
   * 这个方法应该是返回一组成员的键
   *
   * @return a set of member keys as Strings
   * @since 2.8.1
   */
  public Set<String> keySet() {
    return members.keySet();
  }

  /**
   * 返回这棵树中的键/值对的数量
   *
   * @return the number of key/value pairs in the object.
   */
  public int size() {
    return members.size();
  }

  /**
   * 检查指定名称的成员是否在此对象中,如果在返回true,否则返回false
   *
   * @param 正在被检查的成员的名称
   * @return true if there is a member with the specified name, false otherwise.
   */
  public boolean has(String memberName) {
    return members.containsKey(memberName);
  }

  /**
   * 返回指定名称的成员
   *
   * @param 被请求的成员名称
   * @return 返回与名称匹配的成员。如果不存在这样的成员则为null
   */
  public JsonElement get(String memberName) {
    return members.get(memberName);
  }

  /**
   * 将指定的成员作为JsonPrimitive元素返回
   *
   * @param 被请求的成员名
   * @return 返回与指定成员对应的JsonPrimitive
   */
  public JsonPrimitive getAsJsonPrimitive(String memberName) {
    return (JsonPrimitive) members.get(memberName);
  }

  /**
   * 将指定的成员作为一个JsonArray元素返回
   *
   * @param 被请求的成员名
   * @return 返回与指定成员对应的JsonArray
   */
  public JsonArray getAsJsonArray(String memberName) {
    return (JsonArray) members.get(memberName);
  }

  /**
   * 将指定的成员作为一个JsonObject元素返回
   *
   * @param 被请求的成员名
   * @return 返回与指定成员对应的JsonObject
   */
  public JsonObject getAsJsonObject(String memberName) {
    return (JsonObject) members.get(memberName);
  }

  @Override
  public boolean equals(Object o) {
    return (o == this) || (o instanceof JsonObject
        && ((JsonObject) o).members.equals(members));
  }

  @Override
  public int hashCode() {
    return members.hashCode();
  }
}
6.4.2.4 JsonNull
 // 这个类就啥也没有,就是用来表示null的
public final class JsonNull extends JsonElement {
  /**
   * singleton for JsonNull
   *
   * @since 1.8
   */
  public static final JsonNull INSTANCE = new JsonNull();

  /**
   * Creates a new JsonNull object.
   * Deprecated since Gson version 1.8. Use {@link #INSTANCE} instead
   */
  @Deprecated
  public JsonNull() {
    // Do nothing
  }

  /**
   * Returns the same instance since it is an immutable value
   * @since 2.8.2
   */
  @Override
  public JsonNull deepCopy() {
    return INSTANCE;
  }

  /**
   * All instances of JsonNull have the same hash code since they are indistinguishable
   */
  @Override
  public int hashCode() {
    return JsonNull.class.hashCode();
  }

  /**
   * All instances of JsonNull are the same
   */
  @Override
  public boolean equals(Object other) {
    return this == other || other instanceof JsonNull;
  }
}

相关数据结构:

JsonObject: private final LinkedTreeMap<String, JsonElement> members = new LinkedTreeMap<String, JsonElement>();

JsonArray:  private final List<JsonElement> elements;

JsonPrimitive: private static final Class<?>[] PRIMITIVE_TYPES = { int.class, long.class, short.class,
               float.class, double.class, byte.class, boolean.class, char.class, Integer.class, Long.class,
               Short.class, Float.class, Double.class, Byte.class, Boolean.class, Character.class };

这三个类都是JsonElement的子类,不同的是他们的实现不同,JsonObject和JsonArray 可以相互包含,而JsonPrimitive不可以,它是结构最小的元素,从上面可以看出,它是被存储的。
上一篇:Gson序列化LinkedHashMap.Entry失败的探索


下一篇:使用Gson解析含有集合的json数据