Java中的hashCode()方法是如何工作的?

20

我很好奇Java如何通过使用Object API的hashCode()方法生成哈希值?

7个回答

25

ObjecthashCode() 实际上是本地方法,其实现并非纯 Java。至于它的工作原理,Tom Hawtin的这个回答做得很好:

许多人声称 Object.hashCode 将返回内存中对象表示的地址。在现代实现中,对象实际上在内存中移动。相反,一个对象头的区域用于存储该值,该值可能会在首次请求该值时从内存地址中惰性派生。

整个答案都值得一读。


10

Java不会自动生成hashCode(),也就是说这里没有自动发生任何事情。然而,Object会根据对象实例的内存地址生成一个HashCode。大多数类(特别是如果您将其用于任何 Collection API中)都应该实现自己的HashCode(并按照契约实现自己的equals方法)。


1
从Object.java文件中(这通常是通过将对象的内部地址转换为整数来实现的,但Java编程语言不要求使用此实现技术。)- 强调我的。 - user unknown
当GC发生时,这个hashCode会在对象移动后返回不同的值吗? - Jacky
3
hashCode使用内存地址这一想法是一个历史瑕疵,它并不总是返回对象的实际内存地址。参考链接:https://dev59.com/B5Xfa4cB1Zd3GeqPfHRP - Raedwald

6
根据Java平台API文档,计算哈希码是基于对象的32位内部JVM地址。虽然对象在执行过程中会移动(我所知道的唯一原因是垃圾回收器),但哈希码不会改变。因此,当您拥有这样一个对象时:
Person person1 = new Person();
person1.setName("Alex");

Person person2 = new Person();
person2.setName("Alex");

Person person3 = person2;

在这种情况下,person1.hashCode 不等于 person2.hashCode,因为这两个对象的内存地址不同。但是,person2.hashCode 将等于 person3,因为它们指向同一个对象。所以,如果您需要为您的对象使用 hashCode 方法,您必须自己实现它。顺便说一下,String.hashCode 的实现不同。它类似于这样:(C#语法)
public int hashCode(String str)
{
  int h = 0;

  for (int i = 0; i < str.Length; i++)
    h = (h * 31) + str[i];

  return h;
}

编辑:此处未进行溢出检查,因此哈希码可能为正数或负数。


4

Object.hashCode()使用System.identityHashCode(),它基于给定对象的ID号。


3
HashCode()函数有几个选项可以创建哈希码。它设置了JVM启动参数。创建hashCode()的函数是用C++编写的,你可以在这里看到代码。
  • HashCode==0:只返回与对象在内存中的位置无关的随机数。据我所知,种子的全局读写对于拥有大量处理器的系统来说并不理想。
  • HashCode==1:计算哈希码值,不确定从什么值开始,但似乎相当高。
  • HashCode==2:始终返回1的确切标识哈希码。这可用于测试依赖于对象身份的代码。JavaChampionTest在上面的示例中返回Kirk的URL的原因是所有对象都返回相同的哈希码。
  • HashCode==3:计算哈希码值,从零开始。它看起来不是线程安全的,因此多个线程可能生成具有相同哈希码的对象。
  • HashCode==4:这似乎与创建对象的内存位置有关。
  • HashCode>=5:这是Java 8的默认算法,具有每个线程的种子。它使用Marsaglia的异或移位方案生成伪随机数。

这些信息来自这里


2
这怎么能算是对楼主问题的回答呢?这本来可以作为一条评论。 - Mike
为什么我的记录没有响应? - Denis Stepanov
1
这是一个更好的问题答案,并且你添加的编辑也很棒。可惜提问者还是选择了不同的方向。 - Mike

1

Java不会为您生成有意义的hashCode,作为程序员,生成有用的hashCode是您的工作。默认的hashCode只是内存位置。


3
不准确 - 默认的哈希码是基于对象在第一次调用该方法时所处的内存位置; 请参见@Pascal的回答。 - Stephen C

0

hashCode方法输出一个数字值。如果对象不改变,那么对象的哈希码始终相同。需要注意的是,哈希码不一定是唯一的。

默认的hashCode()实现方式是根据对象的地址返回对象的哈希码。JVM会根据对象的地址自动生成这个唯一的数字。

如果两个对象位于同一内存位置(即由两个引用变量引用的同一对象),则两者的哈希码相同;但如果两个对象位于不同的内存位置,则两个对象的哈希码将不同。

你可能问这个问题是因为你需要重写这个方法。但是,什么时候需要重写呢?

默认的hashCode()方法返回基于对象地址的哈希码(对象的唯一标识)。但是,如果我的应用程序需要根据某些不同的参数(而不是对象的地址)来唯一标识对象,则我应该重写hashCode()方法,并根据要求给出实现。

关于这个主题,《Effective Java》有一个重要的注释:

enter image description here

更多信息,请查看此Java hashcode示例


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接