【问题标题】:java hashing objectsjava散列对象
【发布时间】:2012-01-28 13:35:57
【问题描述】:

我希望能够确定我以前是否遇到过一个对象 - 我有一个图形实现,我想看看我是否创建了一个循环,可能是通过使用乌龟遍历 Node 对象/野兔弗洛伊德算法。

但我想避免每次都在我的“已看到”节点列表中进行线性搜索。如果我有一个仅用于键的哈希表,那就太好了。我可以以某种方式散列一个对象吗?无论如何,Java对象不只是对内存中位置的引用吗?我想知道如果是这样的话,碰撞会有多大的问题..

【问题讨论】:

    标签: java hash reference cycle


    【解决方案1】:

    简单的答案是创建一个HashSet,并在您第一次遇到它时将每个节点添加到集合中。

    唯一不起作用的情况是,如果您为节点类重载了 hashCode()equals(Object) 以实现基于节点内容(或其他)的相等性。然后你需要:

    • 使用IdentityHashMap 类,该类使用==System.identityHashcode 而不是equals(Object)hashCode(),或者
    • 使用您自己的对象标识风格自己构建一个哈希表。

    Java 对象不只是对内存中位置的引用吗?

    是和不是。是的,引用由内存地址表示(在大多数 JVM 上)。问题是 1)您无法获取地址,以及 2)当 GC 重新定位对象时它可能会改变。这意味着您不能将对象地址用作哈希码。

    identityHashCode 方法通过返回一个最初基于内存地址的值来处理这个问题。如果您随后为同一个对象再次调用identityHashCode,则可以保证获得与以前相同的值...即使该对象已被重新定位。

    我想知道如果是这样的话,碰撞会有多大的问题..

    identityHashCode 方法产生的哈希值可能会发生冲突。 (也就是说,两个不同的对象可以具有相同的身份哈希码值。)任何使用这些值的东西都必须处理这个问题。 (标准的HashSetIdentityHashMap 类负责处理这些冲突……如果您选择使用它们。)

    【讨论】:

      【解决方案2】:

      我希望能够确定我是否遇到过物体 之前

      使用IdentityHashMap。它是您工作的理想选择,因为它不是 equals 而是 == 实现。

      【讨论】:

      • 引用已死:-(
      【解决方案3】:

      看看HashSet。请注意,为了使对象能够使用 HashSet,它们需要提供 java.lang.Object 类的 hashCodeequals 方法的正确实现。

      【讨论】:

      • 具有身份语义的 hashCode() 和 equals() 的默认实现可能足以满足 OP。
      【解决方案4】:

      您需要为您的对象实现哈希函数。这是通过覆盖java.lang.Object 中定义的hashCode() 来完成的。 HashMapHashSet 等使用此方法来存储对象。在hashCode() 中,由您来计算对象的哈希值。别忘了也实现equals()-方法!

      看看 Java 集合框架 (http://docs.oracle.com/javase/tutorial/collections/)

      【讨论】:

      • 您的第一句话具有误导性:有一个内置的 hashCode() 提供身份语义。
      • 谢谢@kdgregory。第一句已删除。
      猜你喜欢
      • 2014-02-16
      • 1970-01-01
      • 2013-06-22
      • 2012-05-22
      • 2011-04-21
      • 2020-07-08
      • 1970-01-01
      • 2012-09-25
      • 2011-06-07
      相关资源
      最近更新 更多