Java中hashCode的作用是什么?

190
在Java中,obj.hashCode()返回一个值。这个哈希码在编程中有什么用途?

1
这个问题增加了一些更多的细节。 - MaheshVarma
3
这篇文章讲解得非常好。http://eclipsesource.com/blogs/2012/09/04/the-3-things-you-should-know-about-hashcode/ - Vijay Vankhede
8个回答

263

hashCode() 方法被用于 HashMap, HashTable, HashSet等实现了哈希算法的容器中,以对元素进行分桶

hashCode()返回的值被作为桶编号,用于存储集合/映射中的元素,该桶编号即为元素在集合/映射中的地址

当调用contains()方法时,它会获取元素的哈希码,然后找到哈希码指向的桶。如果有多个元素在同一个桶中(多个对象可以拥有相同的哈希码),则使用equals()方法判断这些对象是否相等,并决定contains()方法的返回值是真还是假,或者决定是否将元素添加到集合中。


41
嗨,伙计。非常好的答案,但我找到了一个非常有趣的链接,提供易于理解的实际示例:http://www.coderanch.com/t/321515/java/java/HashCode - Logicalj
谢谢Aishu。现在我对哈希码和桶相关的解释有了清晰的了解。 - Balasubramani
2
如果在同一个桶中找到了多个元素,则使用equals()进行评估。那么,如果只找到一个哈希码匹配的元素,它会直接返回true吗?但是由于多个对象可以具有相同的哈希码,因此必须运行equals()来评估匹配的元素是否相等,否则可能会给您带来意外的结果,我是对的吗? - Saorikido
除了桶之外,哈希码是对象调用的一种方法,用于确定将每个对象存储在内存中的顺序。如果对象相等,则它们的哈希码也必须相等。(反之不成立) - NoName
1
在什么情况下,程序员会手动调用 hashCode() 方法? - Cardinal System
嗨@aishu,你所说的“bucketing”是什么意思? - CodeSlave

41

来自Java文档

返回对象的哈希码值。这个方法是为了哈希表(如java.util.Hashtable提供的哈希表)的效益而支持的。

hashCode的一般合同是:

  • 在Java应用程序执行期间,每当它在同一对象上被多次调用时,hashCode方法必须始终一致地返回相同的整数,前提是等于比较中使用的信息未被修改。这个整数不需要在一个应用程序的多个执行之间保持一致。

  • 如果两个对象根据equals(Object)方法相等,则调用这两个对象上的hashCode方法必须产生相同的整数结果。

  • 如果两个对象根据equals(java.lang.Object)方法是不相等的,则并不要求调用这两个对象上的hashCode方法必须产生不同的整数结果。然而,程序员应该意识到为不相等的对象生成不同的整数结果可能会提高哈希表的性能。

尽可能实用,由Object类定义的hashCode方法确实为不同的对象返回不同的整数。(这通常是通过将对象的内部地址转换为整数来实现的,但这种实现技术不是Java编程语言所要求的。)


这个回答得到了很多赞,但实际上并没有回答问题。这个回答描述了哈希码的含义及其规则,这很好,但问题是有关哈希码如何使用的。 - Russ Jackson

16

hashCode()是一个接受对象并输出数字值的函数。如果对象不发生更改,则对象的哈希码始终相同。

需要存储对象的类,如HashMapHashTableHashSet等,将使用hashCode取模它们内部数组的大小来选择要存储对象的"内存位置"(即数组位置)。

有些情况下可能会发生哈希码冲突(两个对象具有相同的哈希码),这当然需要小心地解决。


15

hashCode() 方法返回的是对象的哈希码,也就是对象在内存中的十六进制地址。

按照定义,如果两个对象是相等的,它们的哈希码也必须相等。如果你重写了 equals() 方法,这会改变两个对象之间的比较方式,从而使得Object类提供的 hashCode() 实现不再有效。因此,如果你重写了equals()方法,那么必须同时重写hashCode() 方法。

本回答摘自Java SE 8官方教程文档


因此,哈希码是内存地址,而不是对象的消息摘要吗? - the_prole

11
一个哈希码是从任何对象生成的数字。
这就是允许对象在Hashtable中快速存储/检索的原因。
想象一下下面的简单例子
在你面前的桌子上,你有九个盒子,每个盒子都标有数字1到9。你还有一堆非常不同的对象要存放在这些盒子里,但一旦它们在那里,你需要尽快找到它们。
你需要的是一种立即决定每个对象放在哪个盒子里的方法。它的工作原理就像一个索引。你想找卷心菜,所以你查找卷心菜在哪个盒子里,然后直接去那个盒子拿。
现在想象一下,你不想麻烦索引,你想立即从对象中找出它属于哪个盒子。
在这个例子中,让我们使用一种非常简单的方法来实现这个目标——对象名称中字母的数量。所以卷心菜放在盒子7中,豌豆放在盒子3中,火箭放在盒子6中,班卓琴放在盒子5中等等。
那么犀牛呢?它有10个字符,所以我们将稍微改变算法,并“环绕”使10个字符的对象放在盒子1中,11个字母的放在盒子2中,依此类推。这应该可以涵盖任何对象。
有时一个盒子里会有多个对象,但如果你正在寻找一枚火箭,比起检查一堆卷心菜、豌豆、班卓琴和犀牛,仍然要快得多。

这是一个哈希码。它是一种从对象中获取数字以便在Hashtable中存储的方法。在Java中,哈希码可以是任何整数,每种对象类型都负责生成自己的哈希码。查询Object的“hashCode”方法。

来源 - 此处


9

虽然哈希码对您的业务逻辑没有任何作用,但在大多数情况下,我们都需要注意它。因为当您的对象被放入基于哈希的容器(HashSetHashMap等)时,容器会放置/获取元素的哈希码。


1
不,它并不会。它只是放置/获取键。hashCode仅用于桶分配。 - user207421

1

hashCode()是由JVM为每个对象创建生成的一个唯一代码。

我们使用hashCode()执行一些哈希相关算法的操作,如Hashtable、Hashmap等。

hashCode()的优点使搜索操作变得容易,因为当我们搜索具有唯一代码的对象时,它有助于找到该对象。

但我们不能说hashCode()是对象的地址。它是JVM为每个对象生成的唯一代码。

这就是为什么现在哈希算法是最流行的搜索算法的原因。


7
哈希码不是唯一的。两个不相等的对象可能返回相同的哈希码。 - Ranielle Canlas

-2

hashCode() 的一个用途是构建捕获机制。看看这个例子:

        class Point
    {
      public int x, y;

      public Point(int x, int y)
      {
        this.x = x;
        this.y = y;
      }

      @Override
      public boolean equals(Object o)
      {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Point point = (Point) o;

        if (x != point.x) return false;
        return y == point.y;
      }

      @Override
      public int hashCode()
      {
        int result = x;
        result = 31 * result + y;
        return result;
      }

class Line
{
  public Point start, end;

  public Line(Point start, Point end)
  {
    this.start = start;
    this.end = end;
  }

  @Override
  public boolean equals(Object o)
  {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    Line line = (Line) o;

    if (!start.equals(line.start)) return false;
    return end.equals(line.end);
  }

  @Override
  public int hashCode()
  {
    int result = start.hashCode();
    result = 31 * result + end.hashCode();
    return result;
  }
}
class LineToPointAdapter implements Iterable<Point>
{
  private static int count = 0;
  private static Map<Integer, List<Point>> cache = new HashMap<>();
  private int hash;

  public LineToPointAdapter(Line line)
  {
    hash = line.hashCode();
    if (cache.get(hash) != null) return; // we already have it

    System.out.println(
      String.format("%d: Generating points for line [%d,%d]-[%d,%d] (no caching)",
        ++count, line.start.x, line.start.y, line.end.x, line.end.y));
}

1
“构建捕获机制”是什么意思?这段代码如何说明它? - user207421

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