[英]Efficiently searching a list to find specific Instance, without using `equals()` or `hashCode()`
我正在实现一个简单的序列化机制。 序列化对象以递归方式拖曳其字段并将其写出到流中。 为了避免无限循环,当遇到对象写入时,它会检查是否以前看过它,如果是,那么它会写一个标记。 这依赖于维护以前见过的对象的可搜索列表。 列表的indexOf()
和contains()
方法不能使用Object.equals
,而必须使用==
,因为对象图中可能有两个对象,它们在数据方面是相同的,但实际上不应该是同一对象。 如果我将简单的Map<Object, Integer>
与下面的示例图一起使用,则会发生一些不良情况:
root: ParentObject (class Parent)
field1: ChildObject1 (class Child)
data: "Hello"
field2: ChildObject2 (class Child)
data: "Hello"
当被序列化时,当.equals()
方法返回true时, Map
被问到是否ChildObject2
编写过ChildObject1
时会找到ChildObject1
。 反序列化后,对象树现在如下所示:
root: ParentObject (class Parent)
field1: ChildObject1 (class Child)
data: "Hello"
field2: <reference to ChildObject1>
现在的问题是,如果某些东西修改了ChildObject1
那么表面上的ChildObject2
也会发生这种变化,这与序列化之前的行为是不同的。 如果这些对象是不可变的,那么这将不是问题,但是这种机制是通用的,不能确保不可变性,在特定情况下,对于对象也不是不可变的,我实际上需要它。
在较低级别的语言中,我将仅基于指针地址创建查找,但这不是这里的选择。
我可以使用简单的List<Object>
,并对list.get(i) == needle
进行线性搜索,但这效率很低。 我首先想到的是一个简单的二进制搜索,但是我该搜索什么呢? 没有要使用的识别信息,也没有密钥。 这似乎排除了使用任何更有效的查找结构的可能性。
过去,我曾使用Unsafe
来输出身份信息(基本上是对象的指针)以进行调试日志记录,但这似乎是“ unsafe”! 在我的脑海中,我想到JVM可以自由移动,例如在GC之后,这也将打破这种方法。
我该如何解决这个问题?
列表的线性扫描将是O(N)
,其中N
是列表长度。 那不是有效的,您也无法使其有效。
您可以使用System.identityHashcode(Object)
计算将与==
兼容的哈希码。
但是,有一个更简单的解决方案。 有一个名为IdentityHashMap
的Map
类,该类非常适合您的用例。 此Map
实现具有O(1)
查找和插入(摊销)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.