对象序列化

对象序列化的目标是将对象保存到磁盘中,或允许在网络中直接传输对象。对象序列化机制允许把内存中的 Java 对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,通过网络将这种二进制流传输到另1个网络节点。其他程序一旦获得了这种二进制流(无论是从磁盘中获取的,还是通过网络获取的) ,都可以将这种二进制流恢复成原来的 Java 对象

如何来使用对象序列化?

前提:

首先,一个类要被序列化,那么它必须实现如下两个接口之一:

  • Serializable
  • Extemalizable

实现着两个接口的作用,其实就是就是标记一个对象是否可以被序列化。所以比如我们有一个类需要被序列化,我们实现Serializable接口就行,无需实现任何方法

序列化工具类:ObjectOutputStream

方法:

  • writeObject()

反序列化工具类:objectInputStream 

方法:

  • readObject()

示例:存储Person类对象

import java.io.*;

/**
 * @ClassName ObjectOutputStreamWriteObjectExample
 * @projectName: object1
 * @author: Zhangmingda
 * @description: Person 类实现序列化接口
 * date: 2021/4/18.
 */
public class ObjectOutputStreamWriteObjectExample {
    //实现接口Serializable可以序列化
    private static class Person implements Serializable {
        String name;
        int age;

        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    //序列化方法
    private static void  writeObject(Person person,String dstPath) {
        try(ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(dstPath))){
            objectOutputStream.writeObject(person);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //反序列化方法
    private static<T> void readObject(String srcPath){
        try(ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(srcPath))){
           T person = (T) objectInputStream.readObject();
            System.out.println(person.getClass());
            System.out.println(person);
            /**
             * class ObjectOutputStreamWriteObjectExample$Person
             * Person{name='钱老大', age=30}
             */
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        Person person = new Person("钱老大",30);
        String dstPath = "输入输出文件读写/src/test/output/object-save.txt";
        writeObject(person,dstPath);
        String srcPath = "输入输出文件读写/src/test/output/object-save.txt";
        readObject(srcPath);
    }
}

示例:带有引用变量的对象序列化

引用类型也必须是可以序列化的。

import java.io.*;

/**
 * @ClassName ObjectOutputStreamWriteObjectExample
 * @projectName: object1
 * @author: Zhangmingda
 * @description: Person 类实现序列化接口
 * date: 2021/4/18.
 */
public class ObjectOutputStreamWriteObjectExample {
    //实现接口Serializable可以序列化
    private static class Person implements Serializable {
        String name;
        int age;
        Job job;

        public Person(String name, int age, Job job) {
            this.name = name;
            this.age = age;
            this.job = job;
        }

        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", job=" + job.getName() +
                    '}';
        }
    }
    private static class Job implements Serializable {
        private String name;

        public Job(String name) {
            this.name = name;
        }
        public String getName() {
            return name;
        }
    }

    //序列化方法
    private static void  writeObject(Person person,String dstPath) {
        try(ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(dstPath))){
            objectOutputStream.writeObject(person);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //反序列化方法
    private static<T> void readObject(String srcPath){
        try(ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(srcPath))){
           T person = (T) objectInputStream.readObject();
            System.out.println(person.getClass());
            System.out.println(person);
            /**
             * class ObjectOutputStreamWriteObjectExample$Person
             * Person{name='钱老大', age=30, job=教师}
             */
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        Person person = new Person("钱老大",30,new Job("教师"));
        String dstPath = "输入输出文件读写/src/test/output/object-save.txt";
        writeObject(person,dstPath);
        String srcPath = "输入输出文件读写/src/test/output/object-save.txt";
        readObject(srcPath);
    }
}

指定哪些字段不需要序列化

比如上面的Person对象,可能有的女生认为年龄是一个秘密,不应该被序列化,怎么办?

transient关键字修饰对应的字段就OK了

示例:private transient

存入:Person{name='钱老大', age=30, job=教师}

读取:Person{name='钱老大', age=0, job=教师} 【不被反序列化的字段置为 对应数据类型默认值】

//序列化写入到文件时transient 未设置,读取时添加了transient,等于对象的类在写入后,读取之前又发生了变化,然后反序列化读取发生

错误类似:local class incompatible: stream classdesc serialVersionUID ......

java extends Serializable作用 java implements serializable_序列化

 


 

解决:类在创建时 添加serialVersionUID字段来保证类发生变化后,也能反序列化成功(不被反序列化的字段置为 对应数据类型默认值)

即:类的升级

import java.io.*;

/**
 * @ClassName ObjectOutputStreamWriteObjectExample
 * @projectName: object1
 * @author: Zhangmingda
 * @description: Person 类实现序列化接口
 * date: 2021/4/18.
 */
public class ObjectOutputStreamWriteObjectExample {
    //实现接口Serializable可以序列化
    private static class Person implements Serializable {
        private static final long serialVersionUID = 769204331117184540L;
        private String name;
        private transient int age;
        private Job job;

        public Person(String name, int age, Job job) {
            this.name = name;
            this.age = age;
            this.job = job;
        }

        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", job=" + job.getName() +
                    '}';
        }
    }
    private static class Job implements Serializable {
        private String name;

        public Job(String name) {
            this.name = name;
        }
        public String getName() {
            return name;
        }
    }

    //序列化方法
    private static void  writeObject(Person person,String dstPath) {
        try(ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(dstPath))){
            objectOutputStream.writeObject(person);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //反序列化方法
    private static<T> void readObject(String srcPath){
        try(ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(srcPath))){
           T person = (T) objectInputStream.readObject();
            System.out.println(person.getClass());
            System.out.println(person);
            /**
             * class ObjectOutputStreamWriteObjectExample$Person
             * Person{name='钱老大', age=30, job=教师}
             */
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
//        Person person = new Person("钱老大",30,new Job("教师"));
//        String dstPath = "输入输出文件读写/src/test/output/object-save.txt";
//        writeObject(person,dstPath);
        String srcPath = "输入输出文件读写/src/test/output/object-save.txt";
        readObject(srcPath);
    }
}