Android基础学习(十五)—— 序列化与反序列化(包括 JSON、GSON))

序列化: 将对象的内容进行流化,将数据分解成字节流,以便存储在文件中或在网络上传输。对象->字节序列

反序列化: 数据转化为对象。字节序列->对象

一、序列化简介

1、进行序列化的原因:

(1)网络传输

网络传输的数据都必须是二进制数据,但是在Java中都是对象,是没有办法在网络中传输的,所以就需要对Java对象进行序列化,并且要求这个序列化是可逆的,也就是说要可以进行反序列化,否则人家都不知道你传递的是啥信息

(2)对象持久化

将内存中的对象状态保存到文件或者数据库中

(3)实现分布式对象

如RMI(远程方法调用)要利用对象序列化运行远程主机上的服务,就像在本地机上运行对象时一样

2、实现序列化的方式

(1)Java原生序列化

需要被序列化的类实现Serializable接口

具体实现:

1)序列化

ObjectOutputStream#writeObject(Object obj)方法

2)反序列化

ObjectInputStream#readObject()方法

缺点:

效率较低,序列化后的流数据比较大

(2)使用第三方的序列化方式

如JSON、Hessian等

3、注意

(1)transient修饰的属性,是不会被序列化的

(2)静态static修饰的属性,是不会被序列化的

二、JSON

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。易于人阅读和编写,同时也易于机器解析和生成。

注意:

1)虽然 JSON 名称中有 JavaScript,但是 JSON 和 JavaScript 的关系仅仅只是 在设计JSON的时候参照了JavaScript的一些语法而已,两者无必然联系。

2)JSON常用于网络数据的交互,以及将某些数据按照JSON的格式写入到文件进行持久化记录

三、GSON

Github:https://github.com/google/gson

GSON是Google提供的用来在Java对象和JSON数据之间进行映射的Java类库。可以将一个JSON字符串转成一个Java对象(反序列化),或反过来(序列化)

在项目中引用GSON:

Gradle:

dependencies{
	implementation 'com.google.code.gson:gson:2.9.1'
}

1、将对象转换为JSON字符串

在需要转换JSON字符串的位置编写代码:

String json = new Gson().toJSON(要转换的对象);

2、将JSON字符串转换为对象

在需要转换Java对象的位置编写代码:

对象 = new Gson().fromJson(JSON字符串, 对象类型.class);

接下来,将从以下几个方面来介绍 GSON 的使用:


1、Java对象序列化与反序列化
public class User {
   @Expose
   private String userName;
   @Expose
   private String password;
   @Expose
   private int age;
   @Expose
   private boolean isStudent;
   @Expose
   private Job job;
   //serialize,是否参与序列化;deserialize,是否参与反序列化
   @Expose(serialize=false, deserialize=false)
   private int test1;

   private transient int test2;

   //无法以class作为字段名
   @SerializedName("class")
   private int cls;

   public User(String userName, String password, int age, boolean isStudent){
       this.userName = userName;
       this.password = password;
       this.age = age;
       this.isStudent = isStudent;
   }

   public String getUserName() {
       return userName;
   }

   public void setUserName(String userName) {
       this.userName = userName;
   }

   public String getPassword() {
       return password;
   }

   public void setPassword(String password) {
       this.password = password;
   }

   public int getAge() {
       return age;
   }

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

   public boolean isStudent() {
       return isStudent;
   }

   public void setStudent(boolean student) {
       isStudent = student;
   }

   public Job getJob() {
       return job;
   }

   public void setJob(Job job) {
       this.job = job;
   }

   public int getTest1() {
       return test1;
   }

   public void setTest1(int test1) {
       this.test1 = test1;
   }

   public int getTest2() {
       return test2;
   }

   public void setTest2(int test2) {
       this.test2 = test2;
   }

   public int getCls() {
       return cls;
   }

   public void setCls(int cls) {
       this.cls = cls;
   }

   @NonNull
   @Override
   public String toString() {
       return "userName=" + userName + ", " +
               "password=" + password + ", " +
               "age=" + age + ", " +
               "isStudent=" + isStudent + ", " +
               "job=" + job + ", " +
               "test1=" + test1 + ", " +
               "test2=" + test2 + ", " +
               "cls=" + cls;
   }
public class ObjectUnitTest {
   public void testObject(){
       User u1 = new User("Lance", "123", 18, false);
       Gson gson = new Gson();

       //序列化
       String json = gson.toJson(u1);
       System.out.println("序列化:" + json);

       //反序列化
       User u2 = gson.fromJson(json, User.class);
       System.out.println("反序列化:" + u2.getUserName());
       System.out.println("反序列化:u2: " + u2);
   }
   public static void main(String args[]){
       ObjectUnitTest out = new ObjectUnitTest();
       out.testObject();
   }
}

结果:

序列化:{"userName":"Lance","password":"123","age":18,"isStudent":false,"test1":0,"class":0}
反序列化:u2: userName=Lance, password=123, age=18, isStudent=false, job=null, test1=0, test2=0, cls=0

Java嵌套对象序列化与反序列化

public class Job {
    private String name;
    private int salary;

    public Job(String name, int salary){
        this.name = name;
        this.salary = salary;
    }

    @Override
    public String toString(){
        return "Job{" +
        "name='" + name + '\'' +
                ", salary = " + salary +
                '}';
    }
}
    public void testNestedObject(){
        User u1 = new User("Lance", "123", 18, false);
        Job job = new Job("工人", 10000);
        u1.setJob(job);

        Gson gson = new Gson();

        String json = gson.toJson(u1);
        System.out.println("序列化::" + json);

        User u2 = gson.fromJson(json, User.class);
        System.out.println("反序列化::" +u2);
    }

结果:

序列化::{"userName":"Lance","password":"123","age":18,"isStudent":false,"job":{"name":"工人","salary":10000},"test1":0,"class":0}
反序列化::userName=Lance, password=123, age=18, isStudent=false, job=Job{name='工人', salary = 10000}, test1=0, test2=0, cls=0

2、Array 和 List 的序列化/反序列化

(1)Array数组的序列化与反序列化

数组类型对象和普通对象一样,使用toJson/fromJson即可完成序列化与返序列化

public void testArray(){
    User[] users1 = new User[3];

    users1[0] = new User("Lance", "123", 18, false);
    users1[1] = new User("Alex", "123", 88, true);

    Gson gson = new Gson();

    String json = gson.toJson(users1);
    System.out.println("序列化:" + json);

    User[] users2 = gson.fromJson(json, User[].class);
    System.out.println("反序列化:" + users2[0]);
    System.out.println("反序列化:" + users2[1]);
    System.out.println("反序列化:" + users2[2]);
}

结果:

序列化:[{"userName":"Lance","password":"123","age":18,"isStudent":false,"test1":0,"class":0},{"userName":"Alex","password":"123","age":88,"isStudent":true,"test1":0,"class":0},null]
反序列化:userName=Lance, password=123, age=18, isStudent=false, job=null, test1=0, test2=0, cls=0
反序列化:userName=Alex, password=123, age=88, isStudent=true, job=null, test1=0, test2=0, cls=0
反序列化:null

(2)List集合的序列化和反序列化

    public void testListObject(){
        List<User> list1 = new ArrayList<>();
        list1.add(new User("Lance", "123", 18, false));
        list1.add(new User("Alex", "123", 88, true));
        list1.add(null);

        Gson gson = new Gson();

        //序列化
        String json = gson.toJson(list1);
        System.out.println("List序列化:" + json);

        //反序列化
        Type type = new TypeToken<List<User>>(){

        }.getType();
        List<User> list2 = gson.fromJson(json, type);  //注意,这里是type
        System.out.println("List反序列化:" + list2.get(0));
        System.out.println("List反序列化:" + list2.get(1));
        System.out.println("List反序列化:" + list2.get(2));
    }

结果:

List序列化:[{"userName":"Lance","password":"123","age":18,"isStudent":false,"test1":0,"class":0},{"userName":"Alex","password":"123","age":88,"isStudent":true,"test1":0,"class":0},null]
List反序列化:userName=Lance, password=123, age=18, isStudent=false, job=null, test1=0, test2=0, cls=0
List反序列化:userName=Alex, password=123, age=88, isStudent=true, job=null, test1=0, test2=0, cls=0
List反序列化:null

注意:

fromJson如果第二个参数为List.class的话,Gson不知道List中的泛型类型是什么,不知道接收数据是哪种类。

TypeToken将泛型指定为List中存储的类型。


3、Map 和 Set 的序列化/反序列化

(1)Map的序列化与反序列化

Map集合类型对象在反序列化时与List一样,需要使用TypeToken完成反序列化

public void testMapObject(){
        Map<String, User> map1 = new HashMap<>();
        //java对象
        map1.put("1", new User("Lance","123", 18, false));
        map1.put("2", new User("Alex","123", 88, true));
        map1.put("3",null);
        map1.put(null, null);
        //Gson提供的Gson对象
        Gson gson = new Gson();
        //序列化
        String json = gson.toJson(map1);
        System.out.println("Map序列化:" + json);

        Type type = new TypeToken<Map<String, User>>(){}.getType();
        Map<String, User> map2 = gson.fromJson(json, type);
        System.out.println("Map反序列化:" + map2.get(null));
        System.out.println("Map反序列化:" + map2.get("1"));
    }

结果:

Map序列化:{"1":{"userName":"Lance","password":"123","age":18,"isStudent":false,"test1":0,"class":0},"2":{"userName":"Alex","password":"123","age":88,"isStudent":true,"test1":0,"class":0}}
Map反序列化:null
Map反序列化:userName=Lance, password=123, age=18, isStudent=false, job=null, test1=0, test2=0, cls=0

(2)Set的序列化与反序列化

Set在反序列化时同样需要使用TypeToken完成反序列化

public void testSetObject(){
        Set<User> set1 = new HashSet<>();
        //java对象
        set1.add( new User("Lance","123", 18, false));
        set1.add(new User("Alex","123", 88, true));
        set1.add(null);

        //Gson提供的Gson对象
        Gson gson = new Gson();

        //序列化
        String json = gson.toJson(set1);
        System.out.println("Set序列化:" + json);


        反序列化
//        Type type = new TypeToken<List<User>>(){}.getType();
//        //如果是 HashSet 类型,则完全可以使用反序列为List,因为ArrayList和HashSet 两者序列化后的 Json 数据一致。
//        List<User> set2 = gson.fromJson(json, type);
//        System.out.println("Set反序列化:" + set2.get(0));
//        System.out.println("Set反序列化:" + set2.get(1));
//        System.out.println("Set反序列化:" + set2.get(2));

        //反序列化
        Type type = new TypeToken<Set<User>>(){}.getType();
        //Set需要使用迭代器,不能直接get
        Set<User> set2 = gson.fromJson(json, type);
        Iterator<User> iterator = set2.iterator();
        while(iterator.hasNext()){
            User next = iterator.next();
            System.out.println("Set反序列化:" + next);
        }
    }

结果:

Set序列化:[null,{"userName":"Lance","password":"123","age":18,"isStudent":false,"test1":0,"class":0},{"userName":"Alex","password":"123","age":88,"isStudent":true,"test1":0,"class":0}]
Set反序列化:null
Set反序列化:userName=Lance, password=123, age=18, isStudent=false, job=null, test1=0, test2=0, cls=0
Set反序列化:userName=Alex, password=123, age=88, isStudent=true, job=null, test1=0, test2=0, cls=0

4、变量值为null时的序列化/反序列化

(1)如果一个变量为NULL,那么按照 GSON 默认的处理为忽略这个字段

    public void testVarNull(){
        User u1 = new User("Lance", "123", 18, false);  //job字段没有赋值,默认为NULL
        //Gson提供的Gson对象
        Gson gson = new Gson();
        //序列化
        String json = gson.toJson(u1);
        System.out.println(json);
        //反序列化
        User u2 = gson.fromJson(json, User.class);
        System.out.println(u2);
    }

结果:

{"userName":"Lance","password":"123","age":18,"isStudent":false,"test1":0,"class":0}
userName=Lance, password=123, age=18, isStudent=false, job=null, test1=0, test2=0, cls=0

当某个属性为null时,Gson在序列化时会忽略这个属性

(2)如果一个集合中的存储的数据为NULL,那么按照GSON默认的处理为不会忽略

List<User> list1 = new ArrayList<>();
list1.add(new User("Lance", "123", 18, false));
list1.add(null);
    
Gson gson = new Gson();
    
//序列化
String json = gson.toJson(list1);
System.out.println("序列化:" + json); 

结果:

序列化:[{"userName":"Lance","password":"123","age":18,"isStudent":false,"test1":0,"class":0},null]

5、控制序列化/反序列化的变量名称

(1)如果希望JSON字符串字段名不用变量名作为Key(比如User类的userName被作为Key),又或者希望JSON字符串中的Key存在Java中的关键字时(如 “class”:18),可以借助 @SerializedName 注解控制 JSON 字段中 Key 的命名。

class User{
    ...
    @SerializedName("class")
    private int cls;
}

(2)如果希望指定GSON对某些字段配置是否参与序列化与反序列化,可以使用 @Expose 注解控制,同时使用 GsonBuilder 创建 Gson 对象。

可以点进去“@Expose”看下源码,可以发现可以设置变量是否参加 序列化/反序列化

默认情况下,变量是可以参加序列化/反序列化的

要使得 “@Expose” 生效,就不是 new Gson() 了,而是new GsonBuilder().excludeFieldWithoutExposeAnnotation().create();

(3)transient关键字的作用:使得变量不参加任何序列化/反序列化

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值