对象流ObjectInputStream和ObjectOutputStream的序列化与反序列化

本文介绍了Java中的对象流ObjectInputStream和ObjectOutputStream,详细阐述了序列化和反序列化的概念,强调对象序列化需实现Serializable接口。讨论了序列化版本号的重要性以及如何处理版本号不一致的问题。此外,提到了transient关键字的作用,它使得被修饰的属性不会参与序列化过程。同时,文中提到在序列化集合时,集合及其元素都需要实现Serializable接口。
摘要由CSDN通过智能技术生成
关于对象流:ObjectInputStream和ObjectOutputStream

1、先来了解一下序列化与反序列化的概念:

序列化:将内存中的java对象分解成数小块,并按照顺序一块一块存储到硬盘文件中,成为对象的序列化。

反序列化:将硬盘中的对象文件,按照顺序还原到内存中,称为对象的反序列化。


2、对象能够序列化,必须实现可序列接口Serializable。

这个Serializable接口中没有任何代码,只是起到一个标志的作用。

java中的接口分两种:普通接口 和 标志接口,期中标志接口中没有任何代码。

Serializable这个标志接口是给JVM看的,虚拟机看到这个接口之后,会为实现类自动生成一个序列化版本号。


3、序列化版本号有什么用?

序列化版本号是让类实现了Serializable接口后,标志着这个类此时的版本。

若以后修改了类中代码,版本号又会改变,以前序列化的文件无法反序列化还原。


4、JVM是如何区分两个可序列化类的类型是否一致?

  • 第一步:先比较两个类的完整类名,就是前面包括了包名。如果类名不一致,那就是两个不同的类型。
  • 第二步:如果类名一致,再比较两个类的序列化版本号是否一致。

假设10年前,你把这个类的对象序列化到文件中。
10年后,因为业务需求而在这个类中添加了一个属性变量,这时序列化版本号会重新自动生成。
这时你再想把10年前的文件反序列化回来,就会报错,序列化版本号不一致。

如何解决这个问题?
把序列化版本号固定成一个常量值,这样的话你后期修改了代码,以前的文件还可以反序列化回来。

如何自定义序列化版本号?

我们通常定义成一个私有long型常量,放在类中的第一行。
且变量名固定为:serialVersionUID,如果不是这个名字的话,JVM还会自动生成一个序列化版本号,等于白做。

参考源代码ArrayList类中的第一行代码:
private static final long serialVersionUID = 8683452581122892189L;


结论:

一个类实现了Serializable接口,最好手动添加序列化版本号。
添加的序列化版本号最好不要和别的产生冲突。

提示:IDEA中可以设置提示生成序列化版本号。
File --> Settings --> Editor --> Inspections --> 搜Serializable class without serialVersionUID,勾上即可。

测试代码:

import java.io.*;

public class Test01 {
   
    public static void main(String[] args) {
   
        ObjectInputStream ois = null;
        ObjectOutputStream oos = null;

        try {
   
            // 这里没有采用追加到文件末尾的方式,而是直接新建一个文件
            oos = new ObjectOutputStream(new FileOutputStream("IOtest\\students"));
            ois = new ObjectInputStream(new FileInputStream("IOtest\\students"));

            // 准备两个可序列化对象,也可以序列化多个不同类型的对象,但要求类实现了Serializable接口
            Student s1 = new Student(1001, "张三");
            Student s2 = new Student(1002, "李四");
            Object obj = new Object();

            // 开始序列化写入
            oos.writeObject(s1);
            oos.writeObject(s2);
            //oos.writeObject(obj);  // 我们知道Object类并没有实现Serializable接口,不能序列化

            // 刷新
            oos.flush();

            // 开始反序列化读取
            Object obj1 = ois.readObject();
            System.out.println(obj1);  // Student{id=1001, name='张三'}

            Object obj2 = ois.readObject();
            System.out.println(obj2);  // Student{id=1002, name='李四'}

        } catch (IOException</
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值