• 序列化、反序列化


    一、序列化、反序列化概念

    序列化(Serialization)是一种将对象以一连串的字节描述的过程,将程序中的对象,放入硬盘(文件)中保存就是序列化,如果不存放在磁盘中,而是一直存放在内存中,会增大内存的消耗;序列化就是将对象的状态信息转换为可以存储或传输的形式的过程;

    反序列化(Deserialization)是一种将这些字节重建成一个对象的过程,将硬盘(文件)中的字节码重新转成对象就是反序列化。

    在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。

    • 把对象的字节序列永久保存到硬盘上,通常存放在一个文件中(序列化对象)

    • 在网络上传送对象的字节序列(网络传输对象) 实际上就是将数据持久化,防止一直存储在内存当中,消耗内存资源。而且序列化后也能更好的便于网络运输何传播

    • 序列化:将java对象转换为字节序列

    • 反序列化:把字节序列回复为原先的java对象

    在这里插入图片描述

    二、实现序列化

    只有实现了Serializable或Externalizable接口的类的对象才能被序列化,否则抛出异常

    import java.io.Serializable;
    public class ZslTest implements Serializable {
        private String name;
        private Integer age;
        private Integer score;
    
        @Override
        public String toString() {
            return "ZslTest{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", score=" + score +
                    '}';
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public Integer getScore() {
            return score;
        }
    
        public void setScore(Integer score) {
            this.score = score;
        }
    }
    
    • 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
    • 36
    • 37
    • 38
    • 39

    测试类

    import java.io.*;
    
    public class test01 {
        public static void serialize(  ) throws IOException {
    
            ZslTest ZslTest = new ZslTest();
            ZslTest.setName("linko");
            ZslTest.setAge( 18 );
            ZslTest.setScore( 1000 );
    
            ObjectOutputStream objectOutputStream =
                    new ObjectOutputStream( new FileOutputStream( new File("ZslTest.txt") ) );
            objectOutputStream.writeObject( ZslTest );
            objectOutputStream.close();
    
            System.out.println("序列化成功!已经生成ZslTest.txt文件");
            System.out.println("==============================================");
        }
    
        public static void deserialize(  ) throws IOException, ClassNotFoundException {
            ObjectInputStream objectInputStream =
                    new ObjectInputStream( new FileInputStream( new File("ZslTest.txt") ) );
            ZslTest ZslTest = (ZslTest) objectInputStream.readObject();
            objectInputStream.close();
    
            System.out.println("反序列化结果为:");
            System.out.println( ZslTest );
        }
    
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            serialize();
            deserialize();
        }
    }
    
    
    • 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

    结果:
    在这里插入图片描述
    从上面可知:
    JDK类库提供的序列化API

    java.io.ObjectOutputStream:表示对象输出流 它的writeObject(Object obj)方法可以对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。
    java.io.ObjectInputStream:表示对象输入流
    它的readObject()方法从源输入流中读取字节序列,再把它们反序列化成为一个对象,并将其返回。

    直接总结:

    • 若对象仅仅实现了Serializable接口,则可以按照以下方式进行序列化和反序列化。 ObjectOutputStream采用默认的序列化方式,对象的非transient的实例变量进行序列化
      ObjcetInputStream采用默认的反序列化方式,对象的非transient的实例变量进行反序列化
    • 若对象仅仅实现了Serializable接口,并且还定义了readObject(ObjectInputStream in)writeObject(ObjectOutputSteam out),则采用以下方式进行序列化与反序列化。
      ObjectOutputStream调用对象的(重写可能存在反序列化风险writeObject(ObjectOutputStream out)的方法进行序列化
      ObjectInputStream会调用对象的(重写可能存在反序列化风险readObject(ObjectInputStream in)的方法进行反序列化
    • 若对象实现了Externalnalizable接口,且对象必须实现readExternal(ObjectInput in)writeExternal(ObjectOutput out)方法,则按照以下方式进行序列化与反序列化。
      ObjectOutputStream调用对象的(重写可能存在反序列化风险writeExternal(ObjectOutput out)的方法进行序列化
      ObjectInputStream调用对象的(重写可能存在反序列化风险readExternal(ObjectInput in)的方法进行反序列化
    • Serializable接口是个空接口,他是一个标记接口,只是做一个标记用!告诉代码只要是实现了Serializable接口的类都是可以被序列化的,然而真正的序列化动作不需要靠它完成。
      在这里插入图片描述
      跟踪源码到ObjectOutputStreamwriteObject0()
      在这里插入图片描述
      在这里插入图片描述

    三、序列化的必要条件

    • 必须是同包,同名。
    • serialVersionUID必须一致。有时候两个类的属性稍微不一致的时候,可以通过将此属性写死值,实现序列化和反序列化。

    证明serialVersionUID必须一致:
    先手动给ZslTest对象加上serialVersionUID,序列化
    在这里插入图片描述
    在这里插入图片描述
    手动删掉serialVersionUID
    在这里插入图片描述
    注释掉序列化,直接反序列化前面已经序列化的对象
    在这里插入图片描述
    总结:

    • serialVersionUID是序列化前后的唯一标识符
    • 默认如果没有人为显式定义过serialVersionUID,那编译器会为它自动声明一个!
    • serialVersionUID序列化ID,可以看成是序列化和反序列化过程中的“暗号”,在反序列化时,JVM会把字节流中的序列号ID和被序列化类中的序列号ID做比对,只有两者一致,才能重新反序列化,否则就会报异常来终止反序列化的过程。
    • 为了serialVersionUID的确定性,建议mplements Serializable的对象,都手动显式地为它声明一个serialVersionUID明确值!

    四、静态变量序列化、父类序列化、 Transient 关键字

    • 被static修饰的字段是不会被序列化的;
      序列化保存的是对象的状态,静态变量属于类的状态,因此序列化并不保存静态变量

    • 想将父类对象也序列化,就需要让父类也实现Serializable 接口

    父类没有实现 Serializable 接口时,JVM是不会序列化父对象的,但是父类不实现Serializable 接口,而他有默认的无参的构造函数,除非在父类无参构造函数中对变量进行初始化,否则父类中的变量值都是默认声明的值,如
    int 型的默认是 0,string 型的默认是 null。

    因为:Java对象的构造必须先有父对象,才有子对象,反序列化也不例外,所以反序列化时,为了构造父对象,只能调用父类的无参构造函数作为默认的父对象。因此当我们取父对象的变量值时,它的值是调用父类无参构造函数后的值。在父类无参构造函数中对变量进行初始化,
    否则的话,父类变量值都是默认声明的值,如 int 型的默认是 0,string 型的默认是 null。

    • Transient 关键字的作用是控制变量的序列化,在变量声明前加上Transient 关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。
      在这里插入图片描述

    五、关于RMI

    RMI相关

    RMI 技术是完全基于 Java 序列化技术的,服务器端接口调用所需要的参数对象来至于客户端,它们通过网络相互传输。这就涉及 RMI
    的安全传输的问题。一些敏感的字段,如用户名密码(用户登录时需要对密码进行传输),我们希望对其进行加密,这时,就可以采用本节介绍的方法在客户端对密码进行加密,服务器端进行解密,确保数据传输的安全性。

  • 相关阅读:
    (二)Ubuntu系统Pytorch环境配置
    21天学习挑战赛之java集合
    JS 读取excel文件内容 和 将json数据导出excel文件
    基于Android的高校移动成绩查询系统的设计与实现
    【MySQL】数据类型
    计算机网络:随机访问介质访问控制之CSMA协议
    TCP 核心问题之 顺序与丢包
    五.Redis_事务秒杀案例
    【计算机毕业设计】基于JSP的房产中介系统的设计与实现
    PLC中ST编程的起保停
  • 原文地址:https://blog.csdn.net/qq_37432174/article/details/128045211