【发布时间】:2012-01-28 13:35:57
【问题描述】:
我希望能够确定我以前是否遇到过一个对象 - 我有一个图形实现,我想看看我是否创建了一个循环,可能是通过使用乌龟遍历 Node 对象/野兔弗洛伊德算法。
但我想避免每次都在我的“已看到”节点列表中进行线性搜索。如果我有一个仅用于键的哈希表,那就太好了。我可以以某种方式散列一个对象吗?无论如何,Java对象不只是对内存中位置的引用吗?我想知道如果是这样的话,碰撞会有多大的问题..
【问题讨论】:
我希望能够确定我以前是否遇到过一个对象 - 我有一个图形实现,我想看看我是否创建了一个循环,可能是通过使用乌龟遍历 Node 对象/野兔弗洛伊德算法。
但我想避免每次都在我的“已看到”节点列表中进行线性搜索。如果我有一个仅用于键的哈希表,那就太好了。我可以以某种方式散列一个对象吗?无论如何,Java对象不只是对内存中位置的引用吗?我想知道如果是这样的话,碰撞会有多大的问题..
【问题讨论】:
简单的答案是创建一个HashSet,并在您第一次遇到它时将每个节点添加到集合中。
唯一不起作用的情况是,如果您为节点类重载了 hashCode() 和 equals(Object) 以实现基于节点内容(或其他)的相等性。然后你需要:
IdentityHashMap 类,该类使用== 和System.identityHashcode 而不是equals(Object) 和hashCode(),或者Java 对象不只是对内存中位置的引用吗?
是和不是。是的,引用由内存地址表示(在大多数 JVM 上)。问题是 1)您无法获取地址,以及 2)当 GC 重新定位对象时它可能会改变。这意味着您不能将对象地址用作哈希码。
identityHashCode 方法通过返回一个最初基于内存地址的值来处理这个问题。如果您随后为同一个对象再次调用identityHashCode,则可以保证获得与以前相同的值...即使该对象已被重新定位。
我想知道如果是这样的话,碰撞会有多大的问题..
identityHashCode 方法产生的哈希值可能会发生冲突。 (也就是说,两个不同的对象可以具有相同的身份哈希码值。)任何使用这些值的东西都必须处理这个问题。 (标准的HashSet 和IdentityHashMap 类负责处理这些冲突……如果您选择使用它们。)
【讨论】:
我希望能够确定我是否遇到过物体 之前
使用IdentityHashMap。它是您工作的理想选择,因为它不是 equals 而是 == 实现。
【讨论】:
看看HashSet。请注意,为了使对象能够使用 HashSet,它们需要提供 java.lang.Object 类的 hashCode 和 equals 方法的正确实现。
【讨论】:
您需要为您的对象实现哈希函数。这是通过覆盖java.lang.Object 中定义的hashCode() 来完成的。 HashMap、HashSet 等使用此方法来存储对象。在hashCode() 中,由您来计算对象的哈希值。别忘了也实现equals()-方法!
看看 Java 集合框架 (http://docs.oracle.com/javase/tutorial/collections/)
【讨论】: