[英]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.