用实际的例子讲清楚Java I/O的序列化流与反序列化流

概念

把对象以流的方式,写入到文件中保存,这种方式称为对象的序列化。
把文件中保存的对象,以流的方式读取出来,这种方式称为对象的反序列化。

序列化流: ObjectOutputStream
  • 构造方法:
    – ObjectOutputStream(OutputStream out):参数 OutputStream为字节输出流

  • 特有的成员方法:
    – void writeObject(Object obj) 将指定的对象写入文件中

  • 将员工对象信息通过序列化流写入文件的例子:

// 员工类支持序列化
class Employee implements Serializable{
    //职员id
    private int id;
    //职员姓名
    private String name;
    //职员性别
    private String sex;
    //职员年龄
    private int age;
    //职员职位
    private String position;
    //入职日期
    private Date hireDate;
    //当前薪水
    private BigDecimal salary;

    public Employee(int id, String name, String sex, int age, String position, Date hireDate, BigDecimal salary) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.position = position;
        this.hireDate = hireDate;
        this.salary = salary;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", age=" + age +
                ", position='" + position + '\'' +
                ", hireDate=" + hireDate +
                ", salary=" + salary +
                '}';
    }
}
/**
 * 对象的序列化流
 *
 * @author zhuhuix
 * @date 2020-06-26
 */
public class ObjectOutputStreamDemo {

    public static void main(String[] args) throws IOException {
        FileOutputStream fileOutputStream = new FileOutputStream("c:\\employee.dat");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        Employee employee =  new Employee(1, "Will", "男", 24, "组员",
                new Date(), BigDecimal.valueOf(20000));
        objectOutputStream.writeObject(employee);
        objectOutputStream.close();
    }

}


反序列化流: ObjectInputStream
  • 构造方法:
    – ObjectInputStream(InputStream out):参数 InputStream 为字节输入流

  • 特有的成员方法:
    – Object readObject() 将文件中的对象读取到流中

  • 通过反序列化流从文件中读取员工对象信息的例子:

/**
 * 对象的序列化流
 *
 * @author zhuhuix
 * @date 2020-06-26
 */
public class ObjectInputStreamDemo {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        FileInputStream fileInputStream = new FileInputStream("c:\\employee.dat");
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        Employee employee = (Employee) objectInputStream.readObject();
        System.out.println(employee.toString());
        objectInputStream.close();
    }

}

在这里插入图片描述

transient关键字

被transient的成员变量不能被序列化,即如果用transient声明一个变量,当对象存储时,它的值不需要维持。

  • 修改一下员工类,将职员职位、入职日期、薪水用transient关键字修饰
// 员工类支持序列化
class Employee implements Serializable {
    //职员id
    private int id;
    //职员姓名
    private String name;
    //职员性别
    private String sex;
    //职员年龄
    private int age;
    //职员职位
    private transient String position;
    //入职日期
    private transient Date hireDate;
    //当前薪水
    private transient BigDecimal salary;

    public Employee(int id, String name, String sex, int age, String position, Date hireDate, BigDecimal salary) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.position = position;
        this.hireDate = hireDate;
        this.salary = salary;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", age=" + age +
                ", position='" + position + '\'' +
                ", hireDate=" + hireDate +
                ", salary=" + salary +
                '}';
    }
}
  • 再次运行序列化保存与反序列化读取的程序,发现用transient关键字修饰的对象属性已不保存数据,读取的信息为空。
    在这里插入图片描述
InvalidClassException

如果类实现了Serializable接口,java编译器在把java文件编译生成class文件时,就会根据类的定义,在class文件中自动添加一个序列号(serialVersionUID)。
如果后续我们修改了原有类的属性,比如增加了属性及方法等,则在重新编译时,java编译器会在编译完成的class文件中生成一个新的序列号,这会造成新的程序在反序列化旧版本的文件时,抛出InvalidClassException异常。
在这里插入图片描述

  • 解决办法:在类文件中定义一个不变的序列号,使得新旧版本能够兼容。
// 员工类支持序列化
class Employee implements Serializable {
	// 人为指定一个序列化号
    private final static long serialVersionUID=1L;
    //职员id
    private int id;
    //职员姓名
    private String name;
    //职员性别
    private String sex;
    //职员年龄
    private int age;
    //职员职位
    private transient String position;
    //入职日期
    private transient Date hireDate;
    //当前薪水
    private transient BigDecimal salary;
    ...
  }

实际案例
  1. 定义一个存储Employee对象的集合;
  2. 在集合中写入多个Employee对象;
  3. 创建一个序列化流;
  4. 使用序列化流的写入方法,将集合进行序列化生成对象的文件。
  5. 创建一个反序化流;
  6. 通过反序列化流读取文件中保存的集合;
  7. 遍历打印集合数据。
/**
 * 通过序列化流与反序列化流保存与读取员工列表
 *
 * @author zhuhuix
 * @date 2020-06-26
 */
public class EmployeeList {
    public static int id = 0;

    public static void main(String[] args) throws IOException,ClassNotFoundException {
        List<Employee> employeeList = new ArrayList<>();

        employeeList.add(new Employee(id++, "Mike", "男", 35, "总经理",
                new Date(), BigDecimal.valueOf(100000)));
        employeeList.add(new Employee(id++, "Tom", "男", 34, "副总经理",
                new Date(), BigDecimal.valueOf(60000)));

        employeeList.add(new Employee(id++, "Jack", "男", 30, "研发部主管",
                new Date(), BigDecimal.valueOf(40000)));
        employeeList.add(new Employee(id++, "Kate", "女", 26, "组员",
                new Date(), BigDecimal.valueOf(20000)));
        employeeList.add(new Employee(id++, "Will", "男", 24, "组员",
                new Date(), BigDecimal.valueOf(20000)));

        employeeList.add(new Employee(id++, "Jerry", "男", 28, "产品部主管",
                new Date(), BigDecimal.valueOf(40000)));
        employeeList.add(new Employee(id++, "Merry", "女", 28, "组员",
                new Date(), BigDecimal.valueOf(20000)));
        employeeList.add(new Employee(id++, "Leo", "男", 27, "组员",
                new Date(), BigDecimal.valueOf(20000)));

        employeeList.add(new Employee(id++, "Rose", "女", 29, "市场部主管",
                new Date(), BigDecimal.valueOf(40000)));
        employeeList.add(new Employee(id++, "Amy", "", 25, "组员",
                new Date(), BigDecimal.valueOf(20000)));
        employeeList.add(new Employee(id++, "Tony", "男", 23, "组员",
                new Date(), BigDecimal.valueOf(20000)));

        // 将集合通过序列化流写入到文件中
        FileOutputStream fileOutputStream = new FileOutputStream("c:\\employeeList.dat");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        objectOutputStream.writeObject(employeeList);
        objectOutputStream.close();

        // 将文件中集合通过反序列化流读取到集合中
        FileInputStream fileInputStream = new FileInputStream("c:\\employeeList.dat");
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        ArrayList<Employee> arrayList = (ArrayList<Employee>) objectInputStream.readObject();
        for (int i = 0; i < arrayList.size(); i++) {
            System.out.println(arrayList.get(i).toString());
        }
        objectInputStream.close();
    }
}

  • 读取打印信息

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智慧zhuhuix

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值