java - 可变对象的 hashCode() 是否有用?

标签 java hash hashcode

我一直在浏览 Java Collections 框架的源代码并注意到 AbstractListAbstractMap 返回它们元素的哈希码的总和作为它们自己的哈希码值。这使得 List 和 Map 实现根据集合的内容返回不同的哈希码值。

据我所知,hashCode() 方法的唯一用途是将元素均匀分布到使用散列的数据结构内的桶中,例如HashSetHashMap。但是,SetMap 契约指定:

The behavior of a set is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is an element in the set.

和:

The behavior of a map is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is a key in the map.

这些合约使得对象可能会根据其状态返回不同的哈希值,这对于在集合中使用和作为映射中的键是危险的。这让我想知道:

  1. 返回变量哈希值是否有意义?
  2. 返回一个常量(每个对象类)散列值不是更好吗?
  3. hashCode() 方法除了用于哈希集合之外,还有什么用处?

最佳答案

Is there a point in returning a variable hash value?

数据结构不知道您是否更改了键或元素的哈希码。这样做会破坏数据结构。但是,如果您在将对象添加到哈希集合之前对其进行变异,并且之后不更改它,这将起作用。

Would not it be better to return a constant hash value?

是的,但该常量必须与 equals 一致,在这种情况下,返回常量的唯一方法是不更改用于创建 hashCode() 的任何字段。

What use can the hashCode() method have besides being used in hash collections

它可用于识别单个对象以用于调试/记录目的,但如果您使用内置的 Object.hashCode() 或 System.identityHashCode(),这会更有用。这是检查两个对象是否是相同引用的快速方法,例如

ByteBuffer bb = ByteBuffer.allocate(1024);
ByteBuffer bb2 = ByteBuffer.allocate(1024);

useBB(bb);
useBB(bb2);

public static void useBB(ByteBuffer bb) {
    System.out.println(Thread.currentThread()+" - Using bb " + System.identityHashCode(bb));
    // do something
}

如果你看到两个线程使用同一个 ByteBuffer,你可能有问题....

you can generate it in a constructor upon instantiation like its done for String objects.

String 的 hashCode 是按需生成的,以减少在不需要 hashCode 的地方创建 String 的开销。注意:拥有 hashCode 为 0 的 String 虽然很少见,但代价很高,除非有人尝试创建 hashCode 为 0 的字符串。

同理,Object的hashCode也是按需生成的。它存储在 Oracle/OpenJDK 的 header 中,初始值为 0 表示未设置,但在首次使用时设置为 1 - 2^31-1。

此程序通过将 hashCode 重置为 0 来对 Object.hashCode() 的成本进行基准测试。

https://github.com/peter-lawrey/Performance-Examples/blob/master/src/main/java/vanilla/java/unsafe/HashCodePerf.java

此程序使用更简单的策略对 Object.HashCode() 进行基准测试。

https://github.com/peter-lawrey/Performance-Examples/blob/master/src/main/java/vanilla/java/unsafe/FasterHashCodePref.java

I meant that you would need to generate it based on final fields, so hash would not change.

这不足以保证 hashCode 不会改变,例如

class A {
    final List<String> strings = new ArrayList<>();

    public int hashCode() {
        return strings.hashCode();
    }
}

您的字段必须是 final 和不可变的。以确保 hashCode 不会改变。但是,如果您不更改它们,它们也不会更改。

关于java - 可变对象的 hashCode() 是否有用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39597464/

相关文章:

ruby - 为什么不能直接在 Ruby 中打印散列?

java - build.gradle中的依赖是自动生成的吗?

java - Keycloak java.lang.NoClassDefFoundError : java/security/acl/Group using Springboot

javascript - 如何在 JS 中迭代哈希并返回所有匹配结果?

performance - 使用链式与开放式寻址的哈希表中的缓存性能

java - Hibernate:惰性初始化与损坏的哈希码/等于难题

java - Object.hashCode() 将在多个 jvm(相同版本)之间保持一致

java - 更改字段后从 Set 中删除对象

java - 如何将多个上下文映射到 Jetty 中的同一个 war 文件?

java - XSD 中的模式验证是否不同?