有效地搜索列表以查找特定的实例,而不使用`equals()`或`hashCode()`

时间:2017-09-26 13:33:44

标签: java serialization

我实现了一个简单的序列化机制。序列化对象以递归方式遍历其字段并将其写入流中。为了避免无限循环,当遇到要写入的对象时,检查它是否在之前看过它,如果是,那么它会写入一个标记。这依赖于维护它之前看到的可搜索的对象列表。列表的indexOf()contains()方法无法使用Object.equals,因此必须使用==,因为对象图中可能包含两个对象在数据方面是相同的,但实际上不应该是同一个对象。如果我使用带有以下示例图的简单Map<Object, Integer>,那么会发生一些不好的事情:

   root: ParentObject (class Parent)
      field1:  ChildObject1 (class Child)
         data: "Hello"
      field2:  ChildObject2 (class Child)
         data: "Hello"

序列化后,当Map被要求查看之前是否已写入ChildObject1ChildObject2找到.equals(),因为 root: ParentObject (class Parent) field1: ChildObject1 (class Child) data: "Hello" field2: <reference to ChildObject1> 方法返回true。反序列化时,对象树现在看起来像这样:

ChildObject1

现在的问题是,如果某些内容修改了ChildObject2,那么明显的List<Object>也会发生这种变化,这与序列化之前发生的行为不同。如果这些对象是不可变的,那么这不会成为问题,但是这种机制是通用的,并且不能确保不变性,并且在特定情况下我实际上需要对象也不是不可变的。

在较低级别的语言中,我只是根据指针地址创建一个查找,但这不是一个选项。

我可以使用简单的list.get(i) == needle,并对Unsafe进行线性搜索,但效率非常低。我的第一个想法是简单的二进制搜索,但我搜索什么?没有识别信息,没有密钥可供使用。这似乎排除了使用任何更有效的查找结构。

我过去曾使用$(function(){ var color, height, width; function makeGrid(){ var table = $('pixel_canvas'); height = $("#input_height").val(); width = $("#input_width").val(); color = $("#colorPicker").val(); console.log(color); console.log(width); console.log(height); for (var i = 0; i<height; i++){ row = table.insertRow(i); for(var j = 0; j<width; j++){ pixel = row.insertCell(j); $(pixel).css({ 'border': 'black solid 1px' }); console.log(pixel); $(pixel).on("click", function(){ $(this).css({'background-color':'color'}); }) } } } $("#sizePicker").on('submit', function(){ makeGrid(); }); });来输出身份信息(基本上是对象的指针),以便进行调试日志记录,但这似乎是,#34;不安全&#34;!在我的脑海里,我有这样的想法,即JVM可以自由地移动,例如在GC之后,这也会破坏这种方法。

我如何解决这个问题?

1 个答案:

答案 0 :(得分:2)

列表的线性扫描将为O(N),其中N是列表长度。这样效率不高,你无法提高效率。

您可以使用System.identityHashcode(Object)来计算与==兼容的哈希码。

但是有一个更简单的解决方案。有一个名为Map的{​​{1}}类,它非常适合您的用例。此IdentityHashMap实施具有Map查找和插入(已摊销)