目录
- 一、定义
- 二、作用
- 三、特点
- 四、语法
- JSON具有以下这些形式:
- 4.1 对象(JSONObject):
- 4.2 数组(JSONArray):
- 4.3 值
- 4.4 字符串
- 4.5 数值
- 五、常用的JSON解析方式
- 5.1 org.json解析
- 5.1.1 常用api
- 5.1.2 get方法与opt方法对比
- 5.1.3 使用示例
- 5.1.3 参考链接
- 5.2 Gson 解析
- 5.2.1 特点
- 5.2.2 常用api
- 5.2.3 常用注解
- 5.2.4 序列化/反序列化接口
- 5.2.5 使用示例
- 5.2.6 参考链接
- 5.3 Jackson解析
- 5.3.1 核心组件
- 5.3.2 注解
- 5.3.3 使用示例
- 5.3.4 参考链接
- 5.4 Fastjson解析
- 5.4.1 特点
- 5.4.2 常用API
- 5.4.3 使用示例
- 5.4.4 参考链接
一、定义
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式
二、作用
数据标记,存储,传输
三、特点
- 读写速度快
- 解析简单
- 轻量级
- 独立于语言,平台
- 具有自我描叙性
四、语法
JSON建构于两种结构:
- “名称/值”对的集合(A collection of name/value pairs)。不同的语言中,它被理解为对象(object),纪录(record),结构(struct),字典(dictionary),哈希表(hash table),有键列表(keyed list),或者关联数组(associative array)。
- 值的有序列表(An ordered list of values)。在大部分语言中,它被理解为数组(array)。
这些都是常见的数据结构。事实上大部分现代计算机语言都以某种形式支持它们。这使得一种数据格式在同样基于这些结构的编程语言之间交换成为可能。
JSON具有以下这些形式:
4.1 对象(JSONObject):
对象是一个无序的“‘名称/值’对”集合。一个对象以“{”(左括号)开始,“}”(右括号)结束。每个“名称”后跟一个“:”(冒号);“‘名称/值’ 对”之间使用“,”(逗号)分隔。
4.2 数组(JSONArray):
数组是值(value)的有序集合。一个数组以“[”(左中括号)开始,“]”(右中括号)结束。值之间使用“,”(逗号)分隔。
4.3 值
值(value)可以是双引号括起来的字符串(string)、数值(number)、true、false、 null、对象(object)或者数组(array)。这些结构可以嵌套。
{
"url": "https://qqe2.com",
"name": "欢迎使用JSON在线解析编辑器",
"array": {
"JSON校验": "http://jsonlint.qqe2.com/",
"Cron生成": "http://cron.qqe2.com/",
"JS加密解密": "http://edit.qqe2.com/"
},
"boolean": true,
"null": null,
"number": 123,
"object": {
"a": "b",
"c": "d",
"e": "f"}
}
4.4 字符串
字符串(string)是由双引号包围的任意数量Unicode字符的集合,使用反斜线转义。一个字符(character)即一个单独的字符串(character string)。字符串(string)与C或者Java的字符串非常相似。
{
"name": "Zero",
}
4.5 数值
数值(number)也与C或者Java的数值非常相似。除去未曾使用的八进制与十六进制格式。除去一些编码细节。
{
"age": 28,
}
五、常用的JSON解析方式
5.1 org.json解析
org.json 是 Android 平台中用于处理 JSON 数据的一个标准库。该库提供了一组类,使开发人员能够轻松地解析和构建 JSON 数据。
5.1.1 常用api
JSONObject
类:JSONObject 类表示一个 JSON 对象,可以包含键值对。通过 JSONObject 类,您可以将 JSON 字符串解析为对象,或者将对象转换为 JSON 字符串。
JSONObject.put(String key, Object value):将指定的键值对添加到 JSON 对象中。
JSONObject.get(String key):获取指定键对应的值。
JSONObject.has(String key):检查 JSON 对象中是否包含指定的键。
JSONObject.toString():将 JSON 对象转换为字符串表示形式。
JSONObject.keys():获取 JSON 对象中所有的键。
JSONArray
类:JSONArray 类表示一个 JSON 数组,可以包含多个元素。通过 JSONArray 类,您可以处理包含多个数据项的 JSON 数组。
JSONArray.put(Object value):向 JSON 数组中添加一个元素。
JSONArray.get(int index):获取指定索引位置的元素。
JSONArray.length():获取 JSON 数组的长度。
JSONArray.toString():将 JSON 数组转换为字符串表示形式。
JSONArray.toList():将 JSON 数组转换为 Java List 对象。
JSONException
类:JSONException 是 org.json 库中定义的异常类,用于处理 JSON 解析和构建过程中的异常情况。
JSONException(String message):使用指定的详细消息构造一个新的异常实例。
JSONException(Throwable cause):使用指定的原因构造一个新的异常实例。
5.1.2 get方法与opt方法对比
opt 相关的 API提供了更安全的方式来获取 JSON 对象中的值,可以处理缺失键或空值的情况,而 get 相关的 API则更适用于确保键存在且值不为 null 的情况下获取值,但在键不存在或值为 null 时会引发异常。
opt 相关的 API
:
opt 相关的方法(如 optString(String key) 和 optInt(String key))是安全的方法,用于从 JSON 对象中获取特定键对应的值。
如果指定键不存在或值为 null,opt 方法会返回一个默认值(如空字符串 " " 或 0)而不会抛出异常。
这些方法适用于处理可能存在缺失键或空值的情况,可以避免空指针异常。
get 相关的 API
:
get 相关的方法(如 getString(String key) 和 getInt(String key))用于从 JSON 对象中获取特定键对应的值,但如果键不存在或值为 null,会抛出异常(如 JSONException)。
这些方法适用于确保 JSON 对象中包含指定键,并且值不为 null 的情况下获取值。
5.1.3 使用示例
void test() {try {// 构建一个 JSON 对象JSONObject jsonObject = new JSONObject();jsonObject.put("name", "Alice");jsonObject.put("age", 25);Log.d("henry", "" + jsonObject);// 构建一个 JSON 数组JSONArray jsonArray = new JSONArray();jsonArray.put("apple");jsonArray.put("banana");jsonArray.put("cherry");Log.d("henry", "" + jsonArray);// 将 JSON 对象和 JSON 数组组合成一个新的 JSON 对象JSONObject mainObject = new JSONObject();mainObject.put("person", jsonObject);mainObject.put("fruits", jsonArray);Log.d("henry", "" + mainObject);// 将 JSON 对象转换为字符串输出String jsonString = mainObject.toString();Log.d("henry", "" + jsonString);// 解析 JSON 字符串JSONObject parsedObject = new JSONObject(jsonString);Log.d("henry", "" + parsedObject.get("person"));} catch (JSONException e) {e.printStackTrace();}}
输出:
5.1.3 参考链接
Android-封装JSON数据(JSON对象/JSON数组)
Android中JSON使用总结
5.2 Gson 解析
Gson 是 Google 提供的一个用于在 Java 对象和 JSON 数据之间进行序列化和反序列化的库。它可以帮助开发人员轻松地将 Java 对象转换为 JSON 格式的数据,也可以将 JSON 数据转换为 Java 对象。
5.2.1 特点
- 简单易用:Gson 提供了简单的 API,使得序列化和反序列化操作变得非常容易。
- 灵活性:Gson 支持处理复杂的 Java 对象结构,包括嵌套对象、集合、数组等。
- 自定义性:可以通过自定义序列化器和反序列化器来控制 Gson 的行为,以满足特定需求。
- 高性能:Gson 在序列化和反序列化过程中具有较高的性能,能够有效地处理大量数据
5.2.2 常用api
Gson gson = new Gson()
: 创建一个 Gson 实例,用于进行序列化和反序列化操作。
GsonBuilder
: Gson 提供了 GsonBuilder 类来配置 Gson 的行为,例如设置日期格式、处理 null 值等。
示例:Gson gson = new GsonBuilder().setDateFormat(“yyyy-MM-dd”).create();
toJson(Object src)
: 将 Java 对象转换为 JSON 格式的字符串。
toJson(Object src, Type typeOfSrc)
: 将 Java 对象转换为 JSON 格式的字符串,支持泛型类型。
toJsonTree(Object src)
: 将 Java 对象转换为 Gson 的 JsonElement 对象,可以进一步处理该对象。
toJson(Object src, Appendable writer)
: 将 Java 对象转换为 JSON 格式并写入到指定的 Appendable 对象中,如 FileWriter、StringWriter 等。
fromJson(String json, Class< T> classOfT)
: 将 JSON 字符串转换为指定类型的 Java 对象。
fromJson(String json, Type typeOfT)
: 将 JSON 字符串转换为指定泛型类型的 Java 对象。
fromJson(JsonElement json, Class< T> classOfT)
: 将 JsonElement 对象转换为指定类型的 Java 对象。
fromJson(Reader json, Class<T> classOfT)
: 从 Reader 对象中读取 JSON 数据并将其转换为指定类型的 Java 对象。
5.2.3 常用注解
- @Expose 该注解用于指定字段是否参与序列化和反序列化。
其中,serialize 参数用于指定字段是否参与序列化,deserialize 参数用于指定字段是否参与反序列化。- @Since 该注解表示字段在指定版本之后才会参与序列化和反序列化。
- @Until 该注解表示字段在指定版本之前才会参与序列化和反序列化。
- @JsonAdapter 该注解指定了使用自定义的 JsonAdapter(JSON 适配器)来序列化和反序列化该字段。
示例
//当将该注解应用于字段时,表示该字段不会参与序列化,
//即在将 Java 对象转换为 JSON 字符串时,该字段不会包含在生成的 JSON 数据中
@Expose(serialize = false)
private String sensitiveData;//当将该注解应用于字段时,表示该字段不会参与序列化,但会参与反序列化,
//即在将 JSON 数据转换为 Java 对象时,可以从 JSON 数据中读取该字段的值。
@Expose(serialize = false, deserialize = true)
private int readOnlyField;//在将 Java 对象转换为 JSON 字符串时,只有在指定版本号(1.0)之后才会包含该字段;
//反之,从 JSON 数据转换为 Java 对象时,只有在指定版本号之后的 JSON 数据才会包含该字段。
@Since(1.0)
private String newField;//该注解表示字段在指定版本之前才会参与序列化和反序列化。在将 Java 对象转换为 JSON 字符串时,只有在指定版本号(1.1)之前才会包含该字段;
//反之,从 JSON 数据转换为 Java 对象时,只有在指定版本号之前的 JSON 数据才会包含该字段。
@Until(1.1)
private String legacyField;//该注解指定了使用自定义的 JsonAdapter(JSON 适配器)来序列化和反序列化该字段。
//通过自定义的 JsonAdapter,可以实现对字段的定制化处理,例如特定格式的日期转换、自定义逻辑等。
@JsonAdapter(UserJsonAdapter.class)
private CustomObject customField;
5.2.4 序列化/反序列化接口
在 Gson 库中,有两个重要的接口用于自定义 JSON 数据的序列化和反序列化过程:JsonSerializer 和 JsonDeserializer。
JsonSerializer 接口 | JsonDeserializer 接口 | |
---|---|---|
作用 | 通过实现 JsonSerializer 接口并重写 serialize 方法,可以指定如何将 Java 对象转换为符合要求的 JSON 格式的数据。 | 通过实现 JsonDeserializer 接口并重写 deserialize 方法,可以指定如何将 JSON 数据转换为 Java 对象。 |
接口 | JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context); | T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException; |
简单示例:
public class GsonError1 {/*** name : java* authors :*/private String name;private List<AuthorsBean> authors;@Overridepublic String toString() {return "GsonError1{" +"name='" + name + '\'' +", authors=" + authors +'}';}public String getName() {return name;}public void setName(String name) {this.name = name;}public List<AuthorsBean> getAuthors() {return authors;}public void setAuthors(List<AuthorsBean> authors) {this.authors = authors;}public static class AuthorsBean {/*** id : 1'* name : Joshua Bloch'*/private String id;private String name;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "AuthorsBean{" +"id='" + id + '\'' +", name='" + name + '\'' +'}';}}static class GsonError1Deserializer implements JsonDeserializer<GsonError1> {@Overridepublic GsonError1 deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {final JsonObject jsonObject = json.getAsJsonObject();final JsonElement jsonTitle = jsonObject.get("name");final String name = jsonTitle.getAsString();JsonElement jsonAuthors = jsonObject.get("authors");GsonError1 gsonError1 = new GsonError1();if (jsonAuthors.isJsonArray()) {//如果数组类型,此种情况是我们需要的//关于context在文章最后有简单说明AuthorsBean[] authors = context.deserialize(jsonAuthors, AuthorsBean[].class);gsonError1.setAuthors(Arrays.asList(authors));} else {//此种情况为无效情况gsonError1.setAuthors(null);}gsonError1.setName(name);return gsonError1;}}public static void test3() {//TODO:String json = "{\n" +" \"name\": \"java\",\n" +" \"authors\": \"\"\n" +"}";GsonBuilder gsonBuilder = new GsonBuilder();//注册TypeAdaptergsonBuilder.registerTypeAdapter(GsonError1.class, new GsonError1Deserializer());Gson gson = gsonBuilder.create();GsonError1 gsonError1 = gson.fromJson(json, GsonError1.class);System.out.println(gsonError1);}public static void main(String... args) {test3();}
}
输出:
5.2.5 使用示例
导入依赖
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
public class Response<T> {public Response(T data, int code, String message) {this.data = data;this.code = code;this.message = message;}T data;int code;String message;@NonNull@Overridepublic String toString() {return "Response{" +"data=" + data +", code=" + code +", message=' " + message + '\'' +'}';}static class Data {public Data(String result) {this.result = result;}String result;@Overridepublic String toString() {return "Data{" +"result='" + result + '\'' +'}';}}public static void main(String[] args) {GsonBean();GsonList();GsonMap();}/*** 先创建Person对象。* 在创建Gson对象。* 调用Gson的String toJson(Object)方法,来将对象转换为json字符串。* 调用Gson的T fromJson()方法,来将json字符串转换为对象。*/static void GsonBean() {Response<Data> dataResponse = new Response<>(new Data("Bean数据"), 1, "成功");Gson gson = new Gson();String json = gson.toJson(dataResponse);System.out.println("Bean数据 json字符串 =" + json);//来将对象转换为json字符串Response<Data> resp = gson.fromJson(json, new TypeToken<Response<Data>>() {}.getType());System.out.println("Bean数据捕获 data =" + resp);// 调用Gson的 <T> t fromJson(String, Class)方法,将Json串转换为对象Response resp2 = gson.fromJson(json, Response.class);System.out.println("Bean数据 =" + resp2);System.out.println("-----------------");}//为什么TypeToken要定义为抽象类?/*** 在进行GSON反序列化时,存在泛型时,可以借助 TypeToken 获取Type以完成泛型的反序列化。但是为什么TypeToken 要被定义为抽象类呢?* 因为只有定义为抽象类或者接口,这样在使用时,需要创建对应的实现类,此时确定泛型类型,编译才能够将泛型signature信息记录到Class元数据中。*/public static void GsonList() {// 先准备一个List集合List<Response> list = new ArrayList<Response>();list.add(new Response(new Data("List数据1"), 10, "成功"));list.add(new Response(new Data("List数据2"), 20, "成功"));// 创建Gson实例Gson gson = new Gson();// 调用Gson的toJson方法String listJson = gson.toJson(list);System.out.println("list数据 json字符串 =" + listJson);// 如果还调用 <T> t fromJson(String, Class)方法,那么返回的虽然还是个List集合,但是集合里面的数据却不是Person对象,而是Map对象List fromJson = gson.fromJson(listJson, List.class);System.out.println("list数据 fromJson 集合数据类型 =" + fromJson.get(0).getClass());// class com.google.gson.internal.LinkedTreeMap//要想获取的List还和之前的一毛一样,通过Gson包提供的TypeToken获取// 调用Gson的 T fromJson(String, Type)将List集合的json串反序列化为List对象List<Response> plist = gson.fromJson(listJson, new TypeToken<List<Response>>() {}.getType());System.out.println("list数据 fromJson TypeToken =" + plist);System.out.println("-----------------");}/*** 转换Map的步骤和转换List的步骤一模一样*/public static void GsonMap() {Map<String, Response> map = new HashMap<>();map.put("p1", new Response(new Data("Map数据1"), 10, "成功"));map.put("p2", new Response(new Data("Map数据2"), 20, "成功"));Gson gson = new Gson();String mapJson = gson.toJson(map);System.out.println("Map数据 json字符串 =" + mapJson);Map<String, Response> jsonMap = gson.fromJson(mapJson, new TypeToken<Map<String, Response>>() {}.getType());System.out.println("Map数据 fromJson TypeToken =" + jsonMap);}}
输出:
5.2.6 参考链接
采用Gson解析含有多种JsonObject的复杂json
Gson的基本使用
5.3 Jackson解析
Jackson 是一个用于处理 JSON 数据的流行 Java 库,它提供了强大且灵活的 API,用于序列化和反序列化 Java 对象与 JSON 数据之间的转换。
5.3.1 核心组件
ObjectMapper
:ObjectMapper 是 Jackson 库中最重要的类之一,用于执行 Java 对象与 JSON 数据之间的转换。它提供了一系列方法,如 writeValueAsString(将 Java 对象转换为 JSON 字符串)、readValue(将 JSON 字符串转换为 Java 对象)等。
JsonNode
:JsonNode 是 Jackson 中表示 JSON 数据的树形结构的抽象类。它可以表示 JSON 对象、JSON 数组、JSON 字符串等,提供了方便的方法来访问和操作 JSON 数据。
JsonParser 和 JsonGenerator
:JsonParser 用于解析 JSON 数据流,而 JsonGenerator 用于生成 JSON 数据流。它们提供了对 JSON 数据的逐个元素访问和生成的功能。
5.3.2 注解
Jackson 提供了一系列注解,用于控制序列化和反序列化过程:
@JsonSerialize 和 @JsonDeserialize:用于指定自定义的序列化和反序列化类。
@JsonProperty:用于指定 Java 对象属性与 JSON 数据字段的映射关系。
@JsonIgnore:用于忽略特定属性的序列化和反序列化。
等等。
5.3.3 使用示例
导入依赖:
implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.8'implementation 'com.fasterxml.jackson.core:jackson-core:2.9.8'implementation 'com.fasterxml.jackson.core:jackson-annotations:2.9.8'
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);binding = ActivityMainBinding.inflate(getLayoutInflater());setContentView(binding.getRoot());testJackson();}public static class User {private String name;private int age;public User() {}public User(String name, int age) {this.name = name;this.age = age;}public void setName(String name) {this.name = name;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public int getAge() {return age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}}public static void testJackson() {try {// 创建 ObjectMapper 对象ObjectMapper objectMapper = new ObjectMapper();// 创建一个 User 对象User user = new User("Bob", 30);// 将 User 对象转换为 JSON 字符串String json = objectMapper.writeValueAsString(user);Log.d("JacksonTest", "Serialized JSON: " + json);// 将 JSON 字符串转换为 User 对象User deserializedUser = objectMapper.readValue(json, User.class);Log.d("JacksonTest", "Deserialized User: " + deserializedUser.getName() + ", " + deserializedUser.getAge());} catch (Exception e) {Log.e("JacksonTest", "Error during Jackson test: " + e.getMessage());}}
输出:
5.3.4 参考链接
Jackson使用详解
5.4 Fastjson解析
Fastjson 是阿里巴巴开源的 JSON 解析库,具有高性能和丰富的功能。
5.4.1 特点
高性能
:Fastjson 在 JSON 解析和生成方面具有优秀的性能,速度快,效率高,被广泛应用于各种场景。
功能丰富
:Fastjson 提供了丰富的功能,支持将 Java 对象序列化为 JSON 字符串,以及将 JSON 字符串反序列化为 Java 对象。同时支持复杂数据结构(如嵌套对象、集合等)的序列化和反序列化。
灵活性
:Fastjson 提供了多种配置选项和定制功能,可以根据需求进行灵活设置,以满足不同的应用场景。
广泛应用
:Fastjson 在阿里巴巴集团内部被大量使用,也被广泛应用于其他公司和开发者的项目中,是业界常用的 JSON 解析库之一。
开源免费
:Fastjson 是开源项目,采用 Apache License 2.0 开源协议,可以免费使用和修改,适合于商业和个人项目。
持续更新
:Fastjson 持续得到维护和更新,不断优化性能和功能,保持与最新的 JSON 标准兼容。
5.4.2 常用API
- 序列化(将 Java 对象转换为 JSON 字符串):
JSON.toJSONString(Object object): 将 Java 对象序列化为 JSON 字符串。
JSON.toJSONString(Object object, SerializerFeature… features): 可以传入序列化配置参数,如日期格式化、空值处理等。- 反序列化(将 JSON 字符串转换为 Java 对象):
JSON.parseObject(String text, Class clazz): 将 JSON 字符串反序列化为指定类型的 Java 对象。
JSON.parseObject(String text, Type type): 将 JSON 字符串反序列化为指定类型的 Java 对象,支持复杂泛型类型。- 序列化和反序列化配置:
SerializerFeature: 序列化配置项,可用于设置日期格式、空值处理、循环引用处理等。
ParserConfig: 反序列化配置,可用于设置反序列化时的特殊处理。- 其他常用方法:
JSONObject: Fastjson 中的 JSON 对象,可以用于创建和操作 JSON 数据。
JSONArray: Fastjson 中的 JSON 数组,可以用于创建和操作 JSON 数据。
JSON.isValid(String text): 判断一个字符串是否为有效的 JSON 格式。
JSON.parseArray(String text): 将 JSON 数组字符串解析为 Java List 对象。
5.4.3 使用示例
导入依赖
implementation 'com.alibaba:fastjson:1.2.78'
public class FastJsonTest {public static class User {private Long id;private String name;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +'}';}}public static class Group {public Group() {}private Long id;private String name;private List<User> users = new ArrayList<User>();public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public List<User> getUsers() {return users;}public void setUsers(List<User> users) {this.users = users;}public void addUser(User user) {users.add(user);}@Overridepublic String toString() {return "Group{" +"id=" + id +", name='" + name + '\'' +", users=" + users +'}';}}public static void main(String[] args) {//序列化Group group = new Group();group.setId(0L);group.setName("admin");User guestUser = new User();guestUser.setId(2L);guestUser.setName("guest");User rootUser = new User();rootUser.setId(3L);rootUser.setName("root");group.addUser(guestUser);group.addUser(rootUser);String jsonString = JSON.toJSONString(group);System.out.println(jsonString);//反序列化//"{}"表示对象,"[]"表示对象数组(List),一定要有getter和setter。String jsonString1 = "{\"id\":0,\"name\":\"admin\",\"users\":[{\"id\":2,\"name\":\"guest\"},{\"id\":3,\"name\":\"root\"}]}";Group group1 = JSON.parseObject(jsonString1, Group.class);System.out.println(group1.getUsers().get(0).toString());System.out.println(group1.toString());//处理时间Date date = new Date(System.currentTimeMillis());System.out.println(JSON.toJSONStringWithDateFormat(date, "yyyy-MM-dd HH:mm:ss.SSS"));System.out.println(JSON.toJSONString(date, SerializerFeature.UseISO8601DateFormat));JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd";System.out.println(JSON.toJSONString(date, SerializerFeature.WriteDateUseDateFormat));}}
输出:
5.4.4 参考链接
Alibaba Fastjson——超好用的JOSN解析库
经过多方调研,最终还是决定禁用FastJson 这篇很有趣,哈哈哈。