一、什么是json?
1. 官方定义
Json(JavaScript Object Notation)是一种轻量级的数据交换格式。易于人阅读和编写,同时也易于机器解析和生成。他基于 JavaScript ProgrammingLanguage,Standard ECMA-262 3rd Edition-December 1999的一个子集。json采用完全独立于语言的文本格式,但是也使用了类似C语言家族的习惯(包括 C、C++ 、C#、Java 、JavaScript、Per1、Python等)。这些特性使Json成为理想的数据交换语言;
json建构和两种结构
- "名称 / 值 " 对的集合( A collection of name/value pairs )。不同语言中,他被理解为对象(Object),记录(record),结构(struct),字典(dictionary), 哈希表(hash table),有键列表(keyed list),或者关联数组(associative array);
- 值的有序列表(An ordered list of value),在大部分语言中,他被理解为数组;
Json具有以下这些形式:
- 对象是一个无序的 " ’名称/值' 对 " 集合。一个对象 以 " { " 开始, " } "结束。每个 ”名称“ 后跟一个 ” :” (冒号) ;" '名称/值‘ 对" 之间使用 “,” (逗号)分割: 对象“‘名称/值’”对集合.png
- 数组是值(value)的有序集合。一个数组以 “[”(左中括号)开始,“]”(右中括号)结束。值之间使用 “,”(逗号)分割: 数组有序集合.png
- 字符串(String)是由双引号包围的任意Unicode字符的集合,使用反斜线转义,一个字符(character)即一个单独的字符串(character string): 字符串.png
- 数值(Number)也与C或者Java中的数值非常相似,除去位层使用的八进制与十六进制格式,除去一些编码细节: 数值.png
- 空白可以加入任何符号之间
2. 简单理解
Json就是一串字符串,只不过元素会使用特定的符号标注
{ } 双括号表示对象
[ ] 中括号表示数组
" " 双引号内是属性或值
: 冒号表示后者是前者的值(这个值可以是字符串、数字、也可以是另一个数组或对象)
例:{“name" : "小苏"} :一个包含name为小苏的对象
[ { "name" : "小苏”},{ "name" : "xiaosu" } ] :表示包含两个对象的数组
{ "name" : [ "小苏","xiaosu" ] } : 简化上一个例子,这是一个拥有name数组的对象
二、Json数据的组装和原始解析
json解析和组装json数据,主要通过Java自带的org.json包中的类: org.json结构.png-
拼接Json数据
1.JSONObject对象,实例JSONObject对象,然后就可以使用put()方法放入需要的数据 2.JSONArray数组,实例JSONObject对象,然后就可以使用put()方法放入需要的数据 3.使用举例
JSONObject jsonObject = new JSONObject(); //定义对象
jsonObject.put("name","小苏"); //存入一个字符串 key是“name” ,值为“小苏”
jsonObject.put("age",28); //存入一个int类型 key为“age”,值为28
System.out.println( jsonObject.toString()); // ----> {"age":28,"name":"小苏"}
JSONArray jsonArray = new JSONArray(); //声明数组
jsonArray.put(1);
jsonArray.put("hah");
jsonArray.put(true);
jsonArray.put(0,"第一");
System.out.println(jsonArray.toString()); // ---> ["第一","hah",true]
jsonObject.put("array",jsonArray); //对象中放入数组
System.out.println(jsonObject.toString()); //----> {"array":["第一","hah",true],"age":28,"name":"小苏"}
-
解析Json数据
当我们对一个Json数据进行解析时,我们应该已经定义好的json的数据结构,所以我们可以根据Json的数据结构进行解析,以下开始进行解析:
如果取值的key不存在则会报异常
1. 所有的 "{}" 看做是一个对象,即JSONObject ,在实例时传入要解析的参数类型
三、解析工具Gson
使用google提供的Gson :github地址
gradle依赖:
implementation 'com.google.code.gson:gson:2.8.5'
以下是依据Gson官网翻译的几个简单使用例子
(一)、Primitives Examples 原始数据例子
Gson gson = new Gson() ;
//Serialization
gson.toJson(1) ; //--> 1
gson.toJson("abcd") ; // --> "abcd"
gson.toJson(new Long(10)) ; // --> 10
int[] values = {1,2,3} ;
gson.toJson(values) ; // ---> [1,2,3]
//Deserialization
int one = gson.fromJson("1",int.class) ;
Integer one = gson.fromJson("1",Integer.class) ;
Lone one = gson.fromJson("1",Long.class) ;
Boolean false = gson.fromJson("false",Boolean.class);
String str = gson.fromJson("\"abcd\"",String.class) ; //--->abcd
String str = gson.fromJson("abcd",String.class) ; //--->abcd
String[] antherStr = gson.fromJson(" [\"abcd\" ]",String[].class) ; //转为了String[] 对象
(二)、Object Examples 对象数据例子
class BagOfPrimitives{
private int value1 = 1 ;
private String value2 = "abcd" ;
private transient int values = 3 ;
private String values4 = null;
}
//Serialization
BagOfPrimitives obj = new BagOfPrimitives() ;
Gson gson = new Gson() ;
String json = gson.toJson(obj) ; // ---> json is : {"value2":"abcd","value1":1}
//Deserialization
BagOfPrimitives obj2 = gson.fromJson(json,BagOfPrimitives.class) ; //----> obj2 is just like obj
Finer points with Objects : Gson处理对象数据中需要注意的细节:
- 推荐并且最好使用私有字段
- 不需要是用任何注释来表示一个字段进行序列化和反序列化,默认情况下当前类(包括父类)中的所有字段都包括在内
- 如果一个字段被标记为transient,默认情况下他会被忽略不包含在Json序列化和反序列化中
会正确处理null - 当序列化时,输出中会省略空字段
- 在反序列化时,Json中缺少的条目会导致将对象中的相应字段设置为其默认值,对象类型为null,数字类型为0 ,布尔类型为false;
- If a field is synthetic, it is ignored and not included in JSON serialization or deserialization.
- 与内部类、匿名类和本地类中的外部类对应的字段被忽略,不包括在序列化和反序列化中
(三)、Nested Classes(including Inner Classes) 嵌套类(包括内部类)
内部类无法被直接序列化,
public class A {
private String a ;
class B {
public String b ;
public B() {
//No args constructor for B
}
}
}
可以在父类中定义内部类在进行序列化
public class A {
private String a ;
private B b ;
class B {
public String b ;
public B( String b) {
this.b = b ;
}
}
public void setA(String a){
this.a = a ;
}
public void setB(B b){
this.b = b ;
}
}
//serialization
A a = new A () ;
a.setA("123");
A.B b = a.new B("456") ;
a.setB(b);
String json = gson.toJson(a); //------> {"a":"123","b":{"b":"456"}}
//Deserialization
A da = gson.fromJson(json, A.class); // ------> 转为了实体类A , da的a为“123”,B的b为“456”;
(四)、Collections Examples (集合例子)
Gson gson = new Gson() ;
List<Integer> list = Arrays.asList(1,2,3,4,5) ;
//Serialization
String json = gson.toJson(list) ; // json is------> [ 1,2,3,4,5]
//Deserialization
Type listType = new TypeToken<List<Integer>>(){}.getType() ; //定义转换类型type
List<Integer> list1 = gson.fromJson(json, listType); //------> list1 is same as list
集合的局限性:Gson可以序列换任意对象的集合,但不能冲他反序列化,因为用户无法指定结果转换的类型,相反,在反序列化时,集合必须是特定的泛型类型。这是有意义的,并且在遵 循量好的Java编码实践时很少出现问题;
四、项目中运用
1、数据结构:{"code":"0","message":"success","data":{} }
2、数据结构:{"code":"0","message":"success","data":[] }
在项目中做网络请求的时候,服务器返回上面两种数据格式,从中可以看到,主要参数为code、message和data,但是data的数据为{} 或为 [ ] ;
具体处理中:可先定义一个模型基类,使用泛型表示data类型:
public class SResult<T>{
private String code ;
private String message ;
private T data ; // T为定义的泛型
//get() set()省略了。。。减少篇幅
}
public class SData{
private String a ;
private String b ;
// get() set()省略了。。。减少篇幅
}
SRresult 为基础模型,定义code 和 message ,另外定义泛型 data ;
SData 为data类型中的一个对象实例;
解析中有以下几种情况:
1、纯对象数据解析:
String json2 = "{\"a\":\"123a\",\"b\":\"123b\"}" ;
//Deserialization
Type type2 = new TypeToken<SData>(){}.getType() ;
SData n = gson.fromJson(json2,type2) ;
//Serialization
String nResult1 = gson.toJson(n) ; //System.out: {"a":"123a","b":"123b"}
String nResult2 = gson.toJson(n,type2) ; //System.out: {"a":"123a","b":"123b"}
2、纯数组数据解析
String json3 = "[{\"a\":\"123a\",\"b\":\"123b\"},{\"a\":\"123a\",\"b\":\"123b\"},{\"a\":\"123a\",\"b\":\"123b\"}]" ;
//Deserialization
Type type3 = new TypeToken<List<SData>>(){}.getType() ;
List<SData> j = gson.fromJson(json3,type3) ;
//Serialization
String jResult1 = gson.toJson(j) ;
String jResult2 = gson.toJson(j,type3) ;
// 序列化结果是一样的
//[{"a":"123a","b":"123b"},{"a":"123a","b":"123b"},{"a":"123a","b":"123b"}]
3、对象嵌套对象的泛型转换
String json1 = "{\"code\":\"100\",\"message\":\"返回值data为对象\",\"data\":{ \"a\":\"123a\",\"b\":\"123b\"}}" ;
//Deserialization
Type type1 = new TypeToken<SResult<SData>>(){}.getType() ;
SResult<SData> m = gson.fromJson(json1, type1);
//Serialization
String result = gson.toJson(m); // System.out: {"code":"100","data":{"a":"123a","b":"123b"},"message":"返回值data为对象"}
String result1 = gson.toJson(m,type1); //System.out: {"code":"100","data":{"a":"123a","b":"123b"},"message":"返回值data为对象"}
4、对象嵌套数组的泛型转换
String json4 = "{\"code\":\"100\",\"message\":\"返回值data为数组\",\"data\":[{\"a\":\"123a\",\"b\":\"123b\"}]}";
//Deserialization
Type type4 = new TypeToken<SResult<List<SData>>>(){}.getType() ;
SResult<List<SData>> k = gson.fromJson(json4,type4);
//Serialization
String kResult1 = gson.toJson(k) ;
String kResult2 = gson.toJson(k,type4) ;
//System.out: {"code":"100","data":[{"a":"123a","b":"123b"}],"message":"返回值data为数组"}
针对泛型Deserialization可封装一个方法:
public <T> SResult<T> deserializationGson(String json){
Type type = new TypeToken<SResult<T>>(){}.getType();
return new Gson().fromJson(json,type) ;
}
调用实例:
String json4 = "{\"code\":\"100\",\"message\":\"返回值data为数组\",\"data\":[{\"a\":\"123a\",\"b\":\"123b\"}]}";
SResult<List<SData>> k = deserializationGson(json4);
String serializationJson = gson.toJson(k) ;
System.out.println("4 對象嵌套数组泛型转换---> " + serializationJson );
//4 對象嵌套数组泛型转换---> {"code":"100","data":[{"a":"123a","b":"123b"}],"message":"返回值data为数组"}
SResult<SData> m = deserializationGson(json1);
serializationJson = gson.toJson(m) ;
System.out.println("1 對象泛型转换---> " + serializationJson );
//1 對象泛型转换---> {"code":"100","data":{"a":"123a","b":"123b"},"message":"返回值data为对象"}
网友评论