Java 序列化流和反序列化流

162 阅读3分钟

序列化流和反序列化流

Snipaste_2022-12-23_22-15-13.png

序列化流/对象操作输出流ObjectOutputStream

  • 可以把Java中的对象写到本地文件中

构造方法

构造方法说明
public ObjectOutputStream(OutputStream out)把基本流包装成高级流

成员方法

成员方法说明
public final void writeObject(Object obj)把对象序列化(写出)到文件中
  • 细节
    • 使用对象输出流将对象保存到文件中会出现NotSerializableException异常
    • 解决方案:需要让JavaBean类实现Serializable接口
    • Serializable接口中是没有抽象方法的,是标记型接口,一旦实现了这个接口,那么就表示当前的JavaBean类是可以被序列化的

使用

  • 利用序列化流将一个对象写入文件中
Student stu = new Student("张三", 18);

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(...));

oos.writeObject(stu);

oos.close();

反序列化流/对象操作输入流ObjectInputStream

  • 可以把序列化到本地文件中的对象,读取到程序中来

构造方法

构造方法说明
public ObjectInputStream(InputStream in)把基本流变成高级流

成员方法

成员方法说明
public Object readObject()把序列化到本地文件中的对象,读取到程序中来
  • readObject方法细节
    • 返回值是Object类型,还需要手动强转

使用

  • 使用反序列化流把文件中的对象读到文件中
ObjectInputStream ois = new ObjectInputStream(new FileInputStream());

Student o = (Student) ois.readObject();

ois.close();

使用细节

  • 使用序列化流将对象写到文件时,需要让JavaBean类实现Serializable接口,否则,会出现NotSerializableException异常

  • 序列化流写到文件中的数据是不能更改的,一旦修改就无法再次读回来了

  • 当我们更改了JavaBean类后,再将文件中的对象读取到程序中时,会抛出InvalidClassException异常

    • 原因:如果一个JavaBean类实现了Serializable接口,说明这个对象是可被序列化的,此时Java底层会根据类中的所有数据进行计算,得到一个long类型的版本号,将对象写入到文件中是也会把版本号写入文件中,如果更改了JavaBean类,对应的版本号也会改变,此时再将文件中的对象读取到程序中时,两者的版本号不匹配,报错
    • 解决方案1:在JavaBean类中手动定义一个永远都不会更改的版本号
    • 解决方案2:对IDEA进行手动设置,在Settings中搜索Serializable,勾选Non-serializable class with 'serialVersionUID'Transient field is not initialized on deserialization 选项
public class Student implements Serializable {
    private static final long serialVersionUID = 1L;
}
  • 如果不想将某些属性序列化到文件中,可以在属性定义前加入transient关键字,该关键字标记的成员变量不参与序列化过程
    • transient关键字:瞬态关键字
    • 作用:不会将当前属性序列化到本地文件中
private transient String address;

读写多个对象

  • 将多个自定义对象序列化读到文件中,但是由于对象的个数不确定,反序列化流该如何读取呢?
    • 一般将先将多个对象先存入到集合中,将集合写入到文件中
Student s1 = new Student("张三", 18);
Student s2 = new Student("李四", 19);
Student s3 = new Student("王五", 20);

ArrayList<Student> list = new ArrayList<>();
list.add(s1);
list.add(s2);
list.add(s3);

ObjectOutStream oos = new ObjectOutStream(FileInputStream("..."));

oos.writeObject(list);

oos.close;

ObjectInputStream ois = new ObjectInputStream(FileInputStream("..."));

ArrayList<Student> list = (ArrayLiat<Student>) ois.readObject();

for (Student stu : list) {
    System.out.println(stu);
}

ois.close();