目录
为了解决对对象,或者是对动态对象数组的持久化,可以对其进行序列化和反序列化的处理。
一.序列化和反序列化的概念
序列化:将对象写入IO流中。比如将Java对象转化为JSON或XML等格式,保存在磁盘中或者通过网络传输。
反序列化:将IO流中恢复对象。与序列化进行相反的操作,将磁盘或者网络中的JSON或XML格式转换成与之前完全一样的对象。
二.序列化的意义
当我们需要存储相同类型的数据时,使用固定长度的记录格式是一个不错的选择。但是,在面向对象程序中创建的对象很少全部都具有相同的类型。例如,可能有一个称为staff的数组,它名义上是一个Employee记录数组,但是实际上却包含诸如Manager这样的子类实例。对此通过对象序列化,可以将对象的状态信息保存在字节序列,并且可以在有需要的时候将这个字节序列通过反序列化的方式转换成对象。
三.序列化的步骤
首先被序列化的的类需要实现Serializable接口或Externalizable接口,通常情况下,实现Serializable接口即可。Serializable接口没有任何方法,所以你不需要在类里面重写任何方法。为了演示方便以下代码片段为不完全片段。
Student类是实现了Serializable接口的实现类,包含姓名和年龄字段
PlainText
public class Student implements Serializable {
//私有字段
private String name;
private int age;
public class Student implements Serializable {
//私有字段
private String name;
private int age;
声明一个存储Student对象的动态数组:
ArrayList<Student> arrayList = new ArrayList<>();
1.序列化
(1)创建一个ObjectOutputStream输出流
(2)调用OjectOutputSteam对象的writeObject ()输出可序列化对象(3)关闭输出流
//存储的文件路径
File file = new File("src\data.txt");
//对对象数组序列化
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
out.writeObject(arrayList);
out.flush();
out.close();
//存储的文件路径
File file = new File("src\data.txt");
//对对象数组序列化
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
out.writeObject(arrayList);
out.flush();
out.close();
2.反序列化
(1)创建一个ObjectInputStream输入流
(2)调用ObjectInputStream对象的readObject ()得到序列化对象
(3)关闭输入流
//存储的文件路径
File file = new File("src\data.txt");
//反序列化
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(file))) {
input = (ArrayList<Student>) in.readObject();
in.close();
//存储的文件路径
File file = new File("src\data.txt");
//反序列化
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(file))) {
input = (ArrayList<Student>) in.readObject();
in.close();
需要注意的是,序列化和反序列化都需要异常处理。
四.序列化的坑
1.子类实现了toString方法,且父类提供了空构造器方法时,子类实现了Serializable接口,父类没有实现,子类可以序列化,但父类字段为空。
2.一个类里面所有的属性必须是可序列化的,这个类才能顺利的序列化。比如,类中存在引用对象,那么这个引用对象必须是可序列化的,这个类才能序列化。
3.当第一次序列化之后,不管如何修改这个对象的属性,都不会对后续的序列化产生影响,反序列化的结果都和第一次相同。
//对对象数组序列化
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
out.writeObject(arrayList);
out.flush();
// arrayList有 student01 和 student02两个对象
// Student student01 = new Student("张三",18);
// Student student02 = new Student("李四",18);
//对第一个对象的年龄进行更改
arrayList.get(0).setAge(2);
out.writeObject(arrayList);
out.flush();
out.close();
结果,序列化和反序列化结果没变
但是我们可以在反序列化后进行操作,然后再序列化,这样就达到了更改的目的。
4.同一对象不会被序列化多次,这正解释了第三个点。
5.建议手动设置serialVersionUID,这能在你修改(如对类增加字段或者修改字段类型)时,序列化和反序列化成功。
private static final long serialVersionUID = 1L;
整理时间:2022-06-07