在 Java 的序列化机制中,TC_REFERENCE
是序列化协议的一部分,用于在序列化和反序列化过程中处理对象引用。它确保在反序列化时保持对象引用的一致性,防止重复创建相同的对象实例。
什么是 TC_REFERENCE
?
TC_REFERENCE
的全称是 “Reference Tag”,表示对已经反序列化过的对象的引用。- 当序列化数据流中某个对象已经被序列化,并且在后续的序列化过程中再次遇到同一个对象时,序列化机制会使用
TC_REFERENCE
而不是重新序列化整个对象。 - 在反序列化过程中,
TC_REFERENCE
用于指向已反序列化对象的缓存,从而确保共享引用关系的一致性。
TC_REFERENCE
的结构
在 Java 序列化流中,TC_REFERENCE
的结构通常如下:
TC_REFERENCE (byte) // 固定值 0x71
handle (int) // 指向已反序列化对象的引用句柄
具体字段解释
-
TC_REFERENCE
(byte):- 固定字节值
0x71
,用于指示该条目是一个引用。
- 固定字节值
-
handle
(int):- 这是一个整数,表示在反序列化过程中已经创建的对象的唯一标识符。
handle
是由序列化流自动生成的,从0x7e0000
开始递增。例如,第一个对象的 handle 为0x7e0000
,第二个为0x7e0001
,依此类推。
TC_REFERENCE
的作用
-
避免对象重复创建:
- 如果一个对象在序列化流中多次出现,使用
TC_REFERENCE
可以避免重新创建新实例,而是使用同一个引用。
- 如果一个对象在序列化流中多次出现,使用
-
维护对象引用关系:
- 在处理循环引用或多个对象共享相同引用的情况下,
TC_REFERENCE
确保反序列化后的对象与序列化前的对象具有相同的引用关系。
- 在处理循环引用或多个对象共享相同引用的情况下,
举例说明
假设我们有以下 Java 类:
import java.io.Serializable;
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
public String name;
public Person friend;
public Person(String name) {
this.name = name;
}
}
现在,我们创建一个包含循环引用的实例:
Person alice = new Person("Alice");
Person bob = new Person("Bob");
alice.friend = bob;
bob.friend = alice;
然后我们对该对象进行序列化:
import java.io.*;
public class SerializeExample {
public static void main(String[] args) throws Exception {
Person alice = new Person("Alice");
Person bob = new Person("Bob");
alice.friend = bob;
bob.friend = alice;
// 序列化
FileOutputStream fileOut = new FileOutputStream("persons.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(alice);
out.close();
// 反序列化
FileInputStream fileIn = new FileInputStream("persons.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
Person deserializedAlice = (Person) in.readObject();
in.close();
System.out.println("Alice's friend: " + deserializedAlice.friend.name);
System.out.println("Bob's friend: " + deserializedAlice.friend.friend.name);
}
}
序列化流的结构
TC_OBJECT (0x73) // Alice 对象
TC_CLASSDESC (0x72) // Person 类描述符
...
handle = 0x7e0000 // Alice 对象的 handle
name = "Alice"
friend -> // Alice 的 friend 指向 Bob 对象
TC_OBJECT (0x73) // Bob 对象
handle = 0x7e0001 // Bob 对象的 handle
name = "Bob"
friend ->
TC_REFERENCE (0x71) // 引用之前的 Alice 对象
handle = 0x7e0000 // 指向 Alice 对象
解释
- 第一次序列化 Alice 对象,分配
handle = 0x7e0000
。 - 序列化 Alice 的 friend(Bob 对象),分配
handle = 0x7e0001
。 - 当序列化 Bob 的 friend 时,发现指向的是已经序列化的 Alice 对象,因此使用
TC_REFERENCE
和handle = 0x7e0000
代替重新序列化 Alice 对象。
输出结果
Alice's friend: Bob
Bob's friend: Alice
总结
TC_REFERENCE
用于处理对象共享引用和循环引用的问题,通过引用句柄避免对象的重复创建。- 这种机制确保在序列化和反序列化时,Java 对象的引用关系保持不变,从而保持对象数据的一致性。
- 在 Java 的
ObjectOutputStream
和ObjectInputStream
中,TC_REFERENCE
的机制使得序列化更加高效,并防止数据冗余。