java 深拷贝实用程序如何保留对象的内部关系?

how does java deep copy utility reserve objects' inner relationships?

我正在使用 apache SerializationUtils 来深度复制对象并发现了一些惊人的东西。例如,对象A有2个成员B1B2,它们都有相同的成员C指的是同一个对象). 深度复制后,A' 被创建,我期待 B1' 有成员 C1'B2' 有成员 C2'。但是 B1'B2' 都有相同的成员 C'.

貌似深拷贝之后,对象的层级和关系还是保持的。这是如何实施的?

我不知道 Apache 库,但很可能它保留了迄今为止复制的实例映射。如果遇到要复制的实例C,它首先检查是否已经存在该实例的副本C'。如果是这样,它会使用现有的副本。如果不是,它会创建 C 的深层副本,给出 C' 并将该副本存储在地图中。

需要考虑的一个要点:我猜想 Apache 的存在性测试基于 == 运算符而不是 equals() 方法,因为 == 运算符将给出最干净的结果,最类似于原始引用结构。否则,恰好满足 equals() 测试的两个不同实例 C1C2 最终将作为一个副本 C'.

让我们将两个引用视为具有 'the same identity' 如果它们指向同一个对象。即,给定:

Object a = ...;
Object b = ...;

那么 ab 是 'identical' 如果成立:a == b,只有当它们指向同一个对象时才会成立。

注意a.equals(b)是不同的;可以将其持有的任何两个引用视为 'equal',但可能涉及 2 个对象。简单的例子:

String a = new String("Hello");
String b = new String("Hello");
a == b; // this is false
a.equals(b); // this is true

可以确定 2 个引用是否 相同 而不仅仅是 相等.

一个简单的检查就是我刚刚向您展示的内容:==,它检查相同而不是相等

SerializationUnits 中的代码很可能使用 WeakHashMap,这是一个映射到标识(或多或少,'the pointer')的映射。 WHM 主要是一个内部实现,但请注意,您始终可以通过 System.identityHashCode 获取身份哈希码,其中 return 是同一对象的相同值,即使该对象已发生变异。理论上,a.hashCode() 可以 return 一个不同的值(对于可变对象,它倾向于),但是 System.identityHashCode(a) 对于任何给定实例在 VM 的生命周期内都是相同的值。

plain jane HashMap 使用 a.hashCode() 知道要查看哪个桶,然后 a.equals(b) 扫描是否相等。

A WeakHashMap 使用 System.identityHashCode(a) 知道要查看哪个桶,然后 a == b 扫描是否相等。

有了这些,编写一个保留层次结构和关系的序列化程序就变得微不足道了。

另请注意,如果没有这种机制,可靠的序列化是不可能的。毕竟,想象一下这个结构:

List<Object> list = new ArrayList<Object>();
list.add(list); // ooooh, recursion!

如果没有像 WeakHashMap 这样的工具,任何序列化此构造的尝试都将导致 WhosebugError,原因很明显。