Gson 使用篇
开篇:在使用Gson之前,我们先聊一下Json, 虽然大部分人都用过,经常用,但有时候并不会太注意细节,写这篇博客也是为了更清晰的了解Gson是如何解析Json,这篇博客主要讲解Json的语法,以及使用Gson如何解析Json,下篇博客讲解Gson解析Json的主要流程及原理,网上很多类似的博客,这里也算自己学习的一个记录,总结。
一. Json 是什么?
Json 是诸多序列化方案的一种,是一种轻量级的数据交换格式,主要用于数据的网络传输,本地存储,数据标记使用。
二. Json 语法格式
#### 2.1 Json构建的两种结构
-
键/值对的集合(A collection of name/value pairs). 不同的语言中,它被理解为对象(Object), 记录(record), 结构(struct), 字典(dictionary),哈希表(hash table), 有键列表(keyed list), 或者关联数组(associative array)
-
值的有序列表(An ordered list of values)。 在大部分语言中,它被理解为数组(array).
-
我们可以理解为两种构造,一种是对象,一种是数组(数组中包含的还是对象)
-
Json语法-Object
开始是一个无序的“key/value”的集合,一个对象以"{"(左括号)开始, “}”(右括号结束)。
每个“key”后面跟一个":"(冒号); “key/value” 对之间使用 “,”(逗号)分隔,格式如下图
json Object的常见的格式如下:
// 这里整体算是一个Object
{
"name": "英语", // 这里是一个key/Value 对, 两个key/value对之间使用 "," 逗号隔开
"score": 99
}
-
Json语法-array
数组的值(value)的有序集合,其中每个value都是一个Object。一个数组以"["(左中括号)开始,以"]"(右中括号)结束。值之间使用","(逗号)分割。
格式如下图:
json array的常见格式如下:
// 最外层的这个{ 是一个Object 它包含了一个名为array的数组,array数组有两个value(每个value又是一个Object) { "array":[ { "name":"name", "age":18 }, { "name":"yingyu", "score":20 } ] }
-
Json语法-value
值(value) 可以是双引号括起来的字符串(string)、数值(number)、‘true’、‘false’、‘null’、对象(Object)或者数组(array)。这些结构都可以嵌套。
如前面,4, 5所述的json语法一个对象(Object)可以包含一个或多个数组,一个数组(array)也可以包含多个对象(Object)
value的类型如下图:
-
-
Json语法-string
字符串(string)是由双引号包围的任意数量的Unicode字符的集合,使用反斜线转义。如下图:
-
Json语法-number
数值(number)也与C或者Java的数值非常相似。除去未曾使用的八进制和十六进制格式。出去一些编码细节
如下图:
三. Json 特点
- 读写速度快
- 解析简单
- 轻量级
- 独立于语言,平台
- 具有自我描述性
四. 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实例
-
简单使用的情况使用new Gson()
-
需要自定义TypeAdapter的,设置格式输出的,总之就是你需要自定义一些配置的,选择new GsonBuilder()的方式
6.2 如何通过Gson对对象进行序列化和反序列化
6.2.1 使用Gson对java bean对象进行序列化
IDE:Android Studio
-
创建一个简单的工程
-
在Gradle中添加 implementation ‘com.google.code.gson:gson:2.8.4’
-
创建两个java bean类
-
创建 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对象进行序列化和反序列化
- 通过扩展TypeAdapter类并将其传递给目标对象的类型来创建自定义适配器。 重写read和write方法以分别执行自定义反序列化和序列化。
class StudentAdapter extends TypeAdapter<Student> {
@Override
public Student read(JsonReader reader) throws IOException {
...
}
@Override
public void write(JsonWriter writer, Student student) throws IOException {
}
}
- 实际使用例子如下:
/**
* 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 接口自定义序列化和反序列化
- 首先看一下如何使用
/**
* 实现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;
}
}
-
在使用之前我们先来了解一下JsonElement 这个类
首先,这个类是一个抽象类,代表着Json字符串中的某一个元素。这个元素可以是一个对象(Object)、可以是一个数组(JsonArray)、可以是一个Java的基本类型(JsonPrimitive)、当然也可以是null(JsonNull);JsonObject,JsonArray, JsonPrimitive,JsonNull都是JsonElement这个抽象类的子类。JsonElement提供了一系列的方法来判断当前的JsonElement各个JsonElement的关系
各个JsonElement的关系可以用如下图标识:
也可以用类图:
JsonObject对象可以看成 key/value的集合,而这些values就是一个个JsonElement,他们的结构可以用如下图表示:
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类:
-
判断JsonElement的类型
-
获取指定类型的JsonElement
-
获取基本类型的值
-
获取基本类型的包装类的值
上面都有注释,大家可以看一下,具体有什么用,我们继续往下看
那么问题来了,这个东西用来表示不同类型的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不可以,它是结构最小的元素,从上面可以看出,它是被存储的。