序列化与反序列化

314 阅读2分钟

「这是我参与2022首次更文挑战的第9天,活动详情查看:2022首次更文挑战」。

序列化就是把对象序列化成字节流或者json的过程,反序列化就是把字节序列恢复成对象的过程。序列化与反序列化在网络传输中有重大作用。常见于我们定义的接口返回数据,或者接收参数的过程中,返回数据就是一个序列化的过程,序列化为字节流。接收数据就是反序列化的过程,反序列化为对象。

一、序列化与反序列化的相关概念

java进行序列化必须实现serialable接口或者Externalizable接口。序列化可以用于对象的保存与复制,数据的远程传输,如feign的调用。 子类和父类序列化,如果子类有实现serialable接口,父类没有,那么序列化时只会将子类字段的属性写入,对父类的属性状态不会写入,反序列化时会调用父类的构造器初始化对象。

二、序列化与反序列化实现

@Data
public class StudentA implements Serializable {

    @Serial
    private static final long serialVersionUID = 2784630026295404274L;

    private static String school = "测试学校";

    private String username;

    private Integer age;

    private Integer sex;
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
    ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("temp"));
    StudentA a = new StudentA();
    a.setUsername("旺旺");
    a.setAge(12);
    a.setSex(1);
    outputStream.writeObject(a);
    ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("temp"));
    StudentA b= (StudentA)inputStream.readObject();
    System.out.println(a);
    System.out.println(b);
}

序列化时那些字段会被序列化呢?

  1. 默认情况下是把非静态的字段和非transient字段会被序列化。
  2. 通过ObjectStreamFiled数组声明要序列化的字段。下面的代码就只会序列化username。
@Data
public class StudentA implements Serializable {

    @Serial
    private static final long serialVersionUID = 2784630026295404274L;

    private static final ObjectStreamField[] serialPersistentFields = {new ObjectStreamField("username",String.class)};

    private static String school = "测试学校";

    private String username;

    private Integer age;

    private Integer sex;
}

三、seriaVersionUID的作用

为啥要使用seriaVersionUID。如果没有seriaVersionUID,那么JVM就会帮我们生成一个seriaVersionUID,JVM是按照类名、类修饰符、构造函数信息、方法名(就是一个空格的修改都会导致生成的UID)等等等信息组成,然后经过SHA信息摘要方法生成。如果不加seriaVersionUID,先序列化,然后修改在类中新增字段,再反序列化,就会出现下图所示的问题,即UID不一致。

image.png