2016-09-26 69 views

回答

4

当您使用ObjectOutputStream序列化对象时,流将'记住'它已写入的对象。当它必须再次写入相同的对象时,它不会再写入整个对象,而是写入一个称为“后退引用”的标识符。

接收方ObjectInputStream也将跟踪接收到的对象,并在读取后退引用时返回它先前读取的同一对象。

如在answer by CoronA中所述,这是用于序列化彼此指向的对象,还用于确保在序列化到另一个JVM时保留一个JVM中的身份相等性。

方法readUnshared(及其计数器部分writeUnshared)用于摆脱此行为:它确保读取(写入)的对象将是唯一的(并且不会作为反向引用重用)。这是相当先进的,我不记得曾经见过或曾经使用它,但是再次,我很少看到序列化的用法。

3

考虑:

class A { 
    B b; 
} 

class B { 
    String s; 
    A a; 
} 

及以下建筑:

A a = new A(); 
a.b = new B(); 
b.a = a; 

如果这样的递归结构是序列化和反序列化应该是功能上是相同的。 b.a不应该是A的任意实例,而应该是引用b的那个实例。

在这种情况下,b.a是反向引用,因为A会在ObjectInputStream的B之前被读取。

+0

这不是什么回参考指的。它与循环引用无关,尽管它们将大大受益于后向引用。 – 4castle

+0

使用'writeUnshared'序列化一个像这样的循环结构会抛出一个'StackOverflowException'。 – 4castle

+1

从我的角度来看,有几种情况需要反向引用。循环引用是其中的一部分。是的 - writeUnshared可能会失败,但在我写这个答案的时候,没有人提到readUnshared。 – CoronA

1

反向引用是对先前已写入/读取到流中的同一对象的引用。把它想象成一个指向流中前一个对象的指针。

反向引用很有用,因为如果它在同一个流中被多次(反)序列化,并且在反序列化时还允许引用相等,它们将极大地减少对象的占用空间。

使用反向引用:

Object obj = new Object(); 
obj == obj // true 
writeObject(obj); 
writeObject(obj); 
Object obj1 = readObject(); 
Object obj2 = readObject(); 
obj1 == obj2 // true 

如果我们不使用反向引用,最后的声明将是false