如果某个类的成员变量的类型不是基本类型或String类型,而是另一个引用类型,那么这个引用类必须是可序列化的,否则拥有该类型成员变量的类也是不可序列化的
如果多次请同一个对象序列化,java只会储存一个对象,后续的都只是存储一个编号,具体的序列化算法如下:
所有保存到磁盘中的对象都有一个序列化编号
当程序试图序列化一个对象时,程序将先检查该对象是否已经被序列化过,只有该对象从未(在本次虚拟机中)被序列化过,系统才会将该对象转换成字节序列并输出
如果某个对象已经序列化过,程序将只是直接输出一个序列化编号,而不是再次重新序列化该对象
Person 类
@Data
public class Person implements Serializable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
Teacher 类拥有 Person 类实例
@Data
public class Teacher implements Serializable {
private String name;
private Person student;
public Teacher(String name, Person student) {
this.name = name;
this.student = student;
}
}
将 Teacher 类多次序列化
public class WriteTeacher {
public static void main(String[] args) {
try (
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("teacher.txt"));
) {
Person per = new Person("孙悟空", 2500);
Teacher t1 = new Teacher("唐僧", per);
Teacher t2 = new Teacher("菩提祖师", per);
// 将对象写入输出流
oos.writeObject(t1);
oos.writeObject(t2);
oos.writeObject(per);
oos.writeObject(t2);
} catch (IOException e) {
e.printStackTrace();
}
}
}
问题来了,序列化的四个对象中,Person 对象是不是同一个?
public class ReadTeacher {
public static void main(String[] args) {
try (
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("teacher.txt"));
){
Teacher t1 = (Teacher) ois.readObject();
Teacher t2 = (Teacher) ois.readObject();
Person p = (Person) ois.readObject();
Teacher t3 = (Teacher) ois.readObject();
System.out.println("t1 的 student 引用和 p 是否相同 " + (t1.getStudent() == p));
System.out.println("t2 的 student 引用和 p 是否相同 " + (t2.getStudent() == p));
System.out.println("t2 和 t3 是否是同一个对象:" + (t2 == t3));
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
如图,序列化一个对象多次,只会保存一次
因为 Java 的序列化机制,我们要注意以下场景:如果多次序列化同一个Java对象时,只有第一次序列化时才会把该Java对象转换成字节序列并输出,这样可能引起一个潜在的问题——当程序序列化一个可变对象时,只有第一次使用writeObject()方法输出时才会将该对象转换成字节序列并输出,当程序再次调用writeObject()方法时,程序只是输出前面的序列化编号,即使后面该对象的实例变量值已被改变,改变的实例变量值也不会被输出