• java 对象序列化


    对象序列化

    序列化    :将java对象转换成字节序列,这些字节序列可以保存在磁盘上,或通过网络传输。

    反序列化:将字节序列转换成java对象。

    对象序列化步骤

    • 需要序列化的对象所对应的类需要实现Serializable接口;
    • 创建一个ObjectOutputStream实例,ObjectOutputStream是一个处理流,需要建立在其他节点流的基础之上;
    // FileInputStream为节点流
     ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt"));
    • 调用ObjectOutputStream的writeObject()方法输出对象;
            // 将person对象写入object.txt文件中
            oos.writeObject(person);

    示例如下:

    定义一个Person类,该类实现Serializable接口

    class Person implements java.io.Serializable {
    
        private String name;
        private int age;
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public void setName(String name) {this.name = name;}
        public String getName() {return name;}
        public void setAge(int age) {this.age = age;}
        public int getAge() {return age;}
    
    }

    创建一个Person类的实例对象,并将该对象写入object.txt文件中。

        public static void main(String[] args) throws IOException {
    
            // FileInputStream为节点流
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt"));
    
            Person person = new Person("Sunwukong", 500);
            // 将person对象写入object.txt文件中
            oos.writeObject(person);
        }

    对象反序列化

    反序列化:将字节序列转换成java对象。

    对象反序列化步骤

    • 创建一个ObjectInputStream实例,ObjectInputStream是一个处理流,需要建立在其他节点流的基础之上;
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt"));
    • 调用ObjectInputStream的readObject()方法读取流中的对象,该方法返回一个Object类型的java对象,如果知道java对象的类型,可以将该对象强制类型转换成其真实类型;
    Person person = (Person) ois.readObject();

     

    示例如下:

    恢复object.txt文件中存储的person对象。

        public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException{
    
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt"));
            Person newPerson = (Person) ois.readObject();
            System.out.println(newPerson.getName());   // 输出Sunwukong
            System.out.println(newPerson.getAge());    // 输出500
        }

    反序列化得到的对象是一个全新的对象,是一个重新建造的对象,与原对象不同。

        public static void main(String[] args) throws IOException, ClassNotFoundException {
    
            // 序列化
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt"));
            Person person = new Person("Sunwukong", 500);
            oos.writeObject(person);
    
            // 反序列化
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt"));
            Person newPerson = (Person) ois.readObject();
            // newPerson是新建的对象,与person不是同一个对象
            System.out.println(person == newPerson); // 输出false
        }

    限制序列化的实例变量

    在一些情况下,一个类的某些实例变量为敏感信息,不希望系统将这些实例变量序列化。

    或某些实例变量不可被序列化。

    通过在实例变量前使用transient关键字,可以指定java序列化时忽略这些实例变量。

    如在Person类中的实例变量age前使用transient关键字修饰,Person实例对象序列化时会忽视该变量

    class Person  {
    
        private String name;
        // transient修饰age变量
        // 对象序列化时会忽略该变量
        private transient int age;
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public void setName(String name) {this.name = name;}
        public String getName() {return name;}
        public void setAge(int age) {this.age = age;}
        public int getAge() {return age;}
    
    }
        public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException{
    
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt"));
            Person newPerson = (Person) ois.readObject();
            System.out.println(newPerson.getName());   // 输出Sunwukong
            // age变量没有序列化,反序列化得到的值为默认值
            System.out.println(newPerson.getAge());    // 输出0
        }

     

    实例变量为引用类型时

    该引用类型必须是可序列化的,否则拥有该实例变量的类是不可序列化的(除非使用transient修饰该实例变量)。

    当对某个对象进行序列化时,系统自动把该对象的实例变量序列化,如果某个实例变量引用到另一个对象,则被引用的对象也会被序列化;

    若果被引用对象的实例变量也引用了其他对象,则被引用的对象也会被实例化;

    . . . . . . .

    这种情况被称为递归序列化。

    示例:

    定义Teacher类,该类的一个实例变量student为引用类型Person。

    class Teacher implements java.io.Serializable {
        private String name;
        // student为引用类型
        private Person student;
    
        public Teacher(String name, Person student) {
            this.name = name;
            this.student = student;
        }
    
        public void setName(String name) {this.name = name;}
        public String getName() {return name;}
        public void setStudent(Person student) {this.student = student;}
        public Person getStudent() {return student;}
    }

    创建Teacher类的实例对象,并将该对象序列化(写入object.txt文件中)

            // 序列化
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt"));
            Person person = new Person("Sunwukong", 500);
            Teacher teacher = new Teacher("Tangseng", person);
            // 将teacher对象写入object.txt时,
            // 同时会将teacher中的引用类型变量student所指向的person对象写入object.txt中
            oos.writeObject(teacher);

    反序列化teacher对象,也可以得到person对象

            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt"));
            Teacher newTeacher = (Teacher) ois.readObject();
            System.out.println(newTeacher.getName());   // 输出Tangseng
            Person newPerson = newTeacher.getStudent();
            System.out.println(newPerson.getName());    // 输出Sunwukong       
            System.out.println(newPerson.getAge());     // 输出500

    多个对象的序列化

    当多个对象序列化时,java序列化机制采用如下算法:

    • 所有保存到磁盘中的对象都有一个序列化编号;
    • 当程序试图序列化一个对象时,程序将先检查该对象是否已经被序列化过,只有该对象从未序列化过,系统才会将该对象序列化;
    • 如果某个对象已经序列化过,程序将只是直接输出一个序列化编号,而不是再次重新序列化该对象。

    示例:

    创建一个Person类实例对象person;

    创建两个Teacher类实例对象t1与t2,两个对象都包含person;

    依次向object.txt文件中写入实例对象t1 、t2、person、t1

        public static void main(String[] args) throws IOException, ClassNotFoundException {
    
            // 序列化
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt"));
            Person person = new Person("Sunwukong", 500);
            Teacher t1 = new Teacher("Tangseng", person);
            Teacher t2 = new Teacher("Putizushi", person);
            // 将以上对象写入object.txt时,
            oos.writeObject(t1);
            oos.writeObject(t2);
            oos.writeObject(person);
            oos.writeObject(t1);
    
    
            // 反序列化
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt"));
            // 依次读取object.txt中的对象
            Teacher newt1 = (Teacher)ois.readObject();
            Teacher newt2 = (Teacher)ois.readObject();
            Person newPerson = (Person) ois.readObject();
            Teacher obj = (Teacher)ois.readObject();
    
            System.out.println(newt1.getStudent() == newt2.getStudent());  // true
            System.out.println(newt1.getStudent() == newPerson);           // true
            System.out.println(newt1 == obj);                              // true
        }

    上述程序只有3个对象被序列化:person、t1、t2。

    oos.writeObject(t1);    // 序列化t1与person
    oos.writeObject(t2); // 序列化t2,person已经被序列化,t2中存放的是person序列化编码
    oos.writeObject(person);
    // person已经被序列化,存放的是person序列化编码
    oos.writeObject(t1);      // t1已经被序列化,存放的是t1序列化编码

    所以,从object.txt中取出对象时

    newPerson与 newt1、newt2中的person都是同一个对象

    obj与newt1也是同一个对象。

    其他

    关于对象序列化有以下几点需要注意:

    对象的类名、实例变量都会被序列化,方法、类变量(static修饰的成员变量)、transient实例变量都不会被序列化。

    序列化对象的实例变量应当也是可序列化的,否则使用transient关键字修饰。

    反序列化对象时必须有序列化对象的class文件。

    反序列化读取对象,必须按实际写入顺序读取。

  • 相关阅读:
    ubuntu 安装nodejs
    在VMware下安装CentOS 7.6
    ogg基础知识整理
    Server2012多用户远程桌面及问题解决记录
    win10中批量新建文件夹
    word中去除所有table键
    PLSQL无法连接(不存在或找不到oci.dll)
    Oracle客户端安装及下载地址
    PLSQL官网下载地址
    问题解决:xampp中phpmyadmin“无法连接:无效的设置”
  • 原文地址:https://www.cnblogs.com/deltadeblog/p/9463643.html
Copyright © 2020-2023  润新知