前言 最近写的插件有些地方需要将我的对象保存在磁盘中,虽然确实也可以使用序列化来完成这一操作,但我还是没有这么做。 我需要将它保存至MySQL里,当然MySQL也支持直接操作二进制数据,不过我总是觉得这样不够优雅。 Srar大佬说可以转成Json,然后再保存。 于是我就这么做了。
Json简介 JSON (JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。 简单来说,就是让你的数据以一种更方便阅读的方式来保存,同时也能很容易的再次被读取进你的程序。 请看下面的代码:(省略了getter和setter)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class Player { private int ID; private boolean online; private int age; private String name; private List<String> introduction; private Map<Integer, Integer> intimacy; public Player (int ID, boolean online, int age, String name, List<String> introduction, Map<Integer, Integer> intimacy) { this .ID = ID; this .online = online; this .age = age; this .name = name; this .introduction = introduction; this .intimacy = intimacy; } @Override public String toString () { return "Player{" + "ID=" + ID + ", online=" + online + ", age=" + age + ", name='" + name + '\'' + ", introduction=" + introduction + ", intimacy=" + intimacy + '}' ; } }
对于一个Player对象:
1 2 3 4 5 6 7 8 List<String> list = new ArrayList<>(); list.add("你好,世界!" ); list.add("我是叁只仓鼠!" ); Map<Integer,Integer> map = new HashMap<>(); map.put(1 ,100 ); map.put(2 ,5000 ); map.put(3 ,-1000 ); Player player = new Player(0 ,true ,18 ,"叁只仓鼠" ,list,map);
如果你用序列化保存……那你对这个存档的编辑工作将会很难进行。 如果你存成一个.txt
1 2 3 4 ID: 0 name: 叁只仓鼠 online: true ......
这样确实很容易编辑,但是写起代码来会有点难受,你得做一大堆关于字符串处理的工作,以及判断各种异常情况…… 所以为什么不用一种简单的方法来做这些呢?
对于刚刚提到的这条数据,如果使用Gson把它转成Json格式:{"ID":0,"online":true,"age":18,"name":"叁只仓鼠","introduction":["你好,世界!","我是叁只仓鼠!"],"intimacy":{"1":100,"2":5000,"3":-100,"4":-900}}
再用工具 格式化一下,就变得非常直观易读了: (Gson也可以支持输出带缩进的json字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 { "ID" : 0 , "online" : true , "age" : 18 , "name" : "叁只仓鼠" , "introduction" : [ "你好,世界!" , "我是叁只仓鼠!" ], "intimacy" : { "1" : 100 , "2" : 5000 , "3" : -100 , "4" : -900 } }
而且格式化之后并不影响程序再次读入这条Json,这样的操作十分便捷,也让我们的数据十分易于操作。
Gson简介 Java语言的json解析器有很多,但是Google开发的Gson是我最喜欢的。Gson 是一个开源的工具库,它使得我们可以便捷的操作Json数据。 导入方式: Maven:
1 2 3 4 5 <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.5</version> </dependency>
Gradle:
1 2 3 dependencies { implementation 'com.google.code.gson:gson:2.8.6' }
Gson构造器 先获取一个Gson构造器,这东西能把你的的对象给直接转成Json,也能把Json转成一个对象。 如果你想使用默认设置,直接new Gson();
或者new GsonBuilder().create();
如果你想修改设置,使用new GsonBuilder().create(); 比如说,你的对象里有存了一个Map<Player,Integer>,这时这个Map的Key是一个复杂对象形式,你想把它转成Json,那么你得先设置一下你的转换器。
1 2 3 4 5 6 Gson gson = new GsonBuilder() .setLenient() .enableComplexMapKeySerialization() .serializeNulls() .setPrettyPrinting() .create();
更多GsonBuilder设置请看Doc 当然默认情况下我们还是直接new GsonBuilder().create();
把你的对象转成Gson 很简单,两行代码
1 2 Gson gson = new GsonBuilder().create(); System.out.println(gson.toJson(player));
输出{"ID":0,"online":true,"age":18,"name":"叁只仓鼠","introduction":["你好,世界!","我是叁只仓鼠!"],"intimacy":{"1":100,"2":5000,"3":-100,"4":-900}}
这里要注意一下,如果你的对象里存有map,而你这个map的key是复杂对象(指除了Number、String、Boolean之外的类对象)的话。 请设置new GsonBuilder().enableComplexMapKeySerialization().create();
把Json转成你的对象 在执行这一步之前你要十分肯定这条Json的每一个元素都与你的对象类型一一确定。 使用gson.fromJson();
这个方法接收两个参数,一个String,一个Class。(或者一个Reader,一个Class ) 如果你从数据流中读取的Json,那你可以直接套个InputStreamReader传给它。后面一个Class是帮助识别的。告诉Gson你这个json对象对应了你Java代码里的哪个类。
1 2 3 4 5 6 7 8 9 10 11 public static void main (String[] args) { Gson gson = new GsonBuilder().create(); File file = new File("E:\\test\\player.json" ); try { InputStreamReader reader = new InputStreamReader(new FileInputStream(file)); Player p = gson.fromJson(reader,Player.class); System.out.println(p.toString()); } catch (FileNotFoundException e) { e.printStackTrace(); } }
输出:Player{ID=0, online=true, age=18, name='叁只仓鼠', introduction=[你好,世界!, 我是叁只仓鼠!], intimacy={1=100, 2=5000, 3=-100, 4=-900}}
部分读取 有时候我们并不是想要直接把一个json转成Java对象,而是读取这条json的部分内容,这时我们可以先把他读成一条JsonElement(json条目)。
JsonParser JsonParser是一个解析器,用于把一条文本解析成一个json对象。 使用也很简单,先new一个出来:JsonParser parser = new JsonParser();
。 然后parser.parse(Reader reader);
或者parser.parse(String string);
具体reader和string是啥你们都懂的。
JsonElement 在读入的时候,解析器并不知道它自己读入的到底是一个对象,还是一个数组,又或者是其他什么的,所以我们在读入的时候只把他当成一条json条目。
1 2 3 4 5 6 7 8 9 10 11 12 13 public static void main (String[] args) { File file = new File("E:\\test\\player.json" ); try { InputStreamReader reader = new InputStreamReader(new FileInputStream(file)); JsonParser parser = new JsonParser(); JsonElement element = parser.parse(reader); } catch (FileNotFoundException e) { e.printStackTrace(); } }
JsonObject 既然很清楚我读的这一条是object,那就先转换一下吧:JsonObject object = element.getAsJsonObject();
然后我就可以读取这条json的数据了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public static void main (String[] args) { File file = new File("E:\\test\\player.json" ); try { InputStreamReader reader = new InputStreamReader(new FileInputStream(file)); JsonParser parser = new JsonParser(); JsonElement element = parser.parse(reader); JsonObject object = element.getAsJsonObject(); System.out.println("ID: " + object.get("ID" )); System.out.println("在线: " + object.get("online" )); System.out.println("年龄: " + object.get("age" )); System.out.println("名称: " + object.get("name" )); } catch (FileNotFoundException e) { e.printStackTrace(); } }
输出:
1 2 3 4 ID: 0 在线: true 年龄: 18 名称: "叁只仓鼠"
值得一提的是,object.get(String string);
这个方法返回的也是一个JsonElement。
JsonArray Json里也有数组存储着,所以在读取出来的时候,我们也要相应地转成Array,才能方便地进行下一步操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public static void main (String[] args) { File file = new File("E:\\test\\player.json" ); try { InputStreamReader reader = new InputStreamReader(new FileInputStream(file)); JsonParser parser = new JsonParser(); JsonElement element = parser.parse(reader); JsonObject object = element.getAsJsonObject(); JsonArray array = object.getAsJsonArray("introduction" ); System.out.println("个人简介:" ); for (int i=0 ;i<array.size();i++) { System.out.println(array.get(i)); } } catch (FileNotFoundException e) { e.printStackTrace(); } }
输出:
1 2 3 个人简介: "你好,世界!" "我是叁只仓鼠!"
复杂对象 在这里有一个稍微有点难的事,就是这一条属性private Map<Integer, Integer> intimacy;
它是一个map,我们应该如何读取呢?这样的话又需要使用到GsonBuilder了,但是这样的话我们得先告诉他我们的HashMap到底长啥样,Key是啥,Value又是啥。 直接HashMap<Integer, Integer> map = gson.fronJson(object.get("intimacy"),new HashMap<Integer, Integer>().getClass());
是行不通的。 这时候我们需要用到反射:Type type = new TypeToken<HashMap<Integer,Integer> >(){}.getType();
需要用到的包:import com.google.gson.reflect.TypeToken;
最后代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public static void main (String[] args) { Gson gson = new GsonBuilder().create(); File file = new File("E:\\test\\player.json" ); try { InputStreamReader reader = new InputStreamReader(new FileInputStream(file)); JsonParser parser = new JsonParser(); JsonElement element = parser.parse(reader); JsonObject object = element.getAsJsonObject(); Type type = new TypeToken<HashMap<Integer,Integer> >(){}.getType(); HashMap map = gson.fromJson(object.get("intimacy" ),type); System.out.println(map); } catch (FileNotFoundException e) { e.printStackTrace(); } }
本章完 如果本篇文章对你有帮助,请为我提供一个吃冰激凌的机会! (热死了QAQ)