Java Objects.hash() vs Objects.hashCode() – Java Objects.hash() vs Objects.hashCode()

最后修改: 2021年 5月 14日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.绪论

A hashcode is a numeric representation of the contents of an object.

哈希码是一个对象的内容的数字表示。

In Java, there are a few different methods we can use to get a hashcode for an object:

在Java中,我们可以用一些不同的方法来获取一个对象的哈希码。

  • Object.hashCode() 
  • Objects.hashCode() – introduced in Java 7
  • Objects.hash() – introduced in Java 7

In this tutorial, we’re going to look at each of those methods. First, we’ll start with definitions and basic examples. After we have the basic usage down, we’ll dig into the differences between them and the ramifications those differences may have.

在本教程中,我们将对这些方法中的每一种进行研究。首先,我们将从定义和基本例子开始。在我们掌握了基本的用法之后,我们将深入探讨它们之间的区别以及这些区别可能产生的影响。

2. Basic Usage

2.基本使用方法

2.1. Object.hashCode()

2.1.Object.hashCode()

We can use the Object.hashCode() method to retrieve the hashcode of an object. It’s very similar to Objects.hashCode() except that we can’t use it if our object is null.

我们可以使用Object.hashCode()方法来检索一个对象的哈希代码。它与Objects.hashCode()非常相似,只是如果我们的对象是null,我们就不能使用它。

With that said, let’s call Object.hashCode() on two identical Double objects:

既然如此,让我们在两个相同的Double对象上调用Object.hashCode()

Double valueOne = Double.valueOf(1.0012);
Double valueTwo = Double.valueOf(1.0012);
        
int hashCode1 = valueOne.hashCode();
int hashCode2 = valueTwo.hashCode();
        
assertEquals(hashCode1, hashCode2);

As expected, we receive identical hashcodes.

正如预期的那样,我们收到了相同的哈希码。

In contrast, now let’s call Object.hashCode() on a null object with the expectation that a NullPointerException is thrown:

相反,现在让我们在一个null对象上调用Object.hashCode(),期望抛出NullPointerException

Double value = null;
value.hashCode();

2.2. Objects.hashCode()

2.2.Objects.hashCode()

Objects.hashCode() is a null-safe method we can use to get the hashcode of an object. Hashcodes are necessary for hash tables and the proper implementation of equals().

Objects.hashCode()是一个无效安全的方法,我们可以用它来获取一个对象的哈希代码。哈希码对于哈希表和equals()的正确实现是必要的。

The general contract for a hashcode as specified in the JavaDoc is:

JavaDoc中规定的哈希代码的一般契约是:。

  • That the returned integer be the same each time it’s called for an unchanged object during the same execution of the application
  • For two objects that are equal according to their equals() method, return the same hashcode

Although it’s not a requirement, distinct objects return different hashcodes as much as possible.

虽然这不是一个要求,但不同的对象尽可能地返回不同的哈希代码。

First, let’s call Objects.hashCode() on two identical strings:

首先,让我们对两个相同的字符串调用Objects.hashCode()

String stringOne = "test";
String stringTwo = "test";
int hashCode1 = Objects.hashCode(stringOne);
int hashCode2 = Objects.hashCode(stringTwo);
        
assertEquals(hashCode1, hashCode2);

Now, we expect the returned hashcodes to be identical.

现在,我们希望返回的哈希码是相同的。

On the other hand, if we provide a null to Objects.hashCode(), we’ll get zero back:

另一方面,如果我们向Objects.hashCode()提供一个null,我们会得到0的回报。

String nullString = null;
int hashCode = Objects.hashCode(nullString);
assertEquals(0, hashCode);

2.3. Objects.hash()

2.3.Objects.hash()

Unlike Objects.hashCode(), which takes only a single object, Objects.hash() can take one or more objects and provides a hashcode for them. Under the hood, the hash() method works by putting the supplied objects into an array and calling Arrays.hashCode() on them. If we provide only one object to the Objects.hash() method, we can’t expect the same results as calling Objects.hashCode() on the object.

Objects.hashCode()不同的是,Objects.hash()可以接受一个或多个对象并为它们提供一个哈希代码。在引擎盖下,hash()方法的工作原理是将提供的对象放入一个数组,并对其调用Arrays.hashCode()如果我们只提供一个对象给Objects.hash()方法,我们不能期待与对对象调用Objects.hashCode()一样的结果。

First, let’s call Objects.hash() with two pairs of identical strings:

首先,让我们用两对相同的字符串调用Objects.hash()

String strOne = "one";
String strTwo = "two";
String strOne2 = "one";
String strTwo2 = "two";
        
int hashCode1 = Objects.hash(strOne, strTwo);
int hashCode2 = Objects.hash(strOne2, strTwo2);
        
assertEquals(hashCode1, hashCode2);

Next, let’s call Objects.hash() and Objects.hashCode() with a single string:

接下来,让我们用一个字符串调用Objects.hash()Objects.hashCode()

String testString = "test string";
int hashCode1 = Objects.hash(testString);
int hashCode2 = Objects.hashCode(testString);
        
assertNotEquals(hashCode1, hashCode2);

As expected, the two hashcodes returned do not match.

正如预期的那样,返回的两个哈希码并不匹配。

3. Key Differences

3.关键差异

In the previous section, we hit on the key difference between Objects.hash() and Objects.hashCode(). Now, let’s dig into it a little deeper so we can understand some of the ramifications.

在上一节中,我们提到了Objects.hash()Objects.hashCode()之间的关键区别。现在,让我们更深入地挖掘它,以便我们能够理解一些影响。

If we need to override one of our class’s equals() method, it’s critical that we properly override hashCode() as well.

如果我们需要覆盖我们类的一个equals()方法,关键是我们也要正确覆盖hashCode()

Let’s start by creating a simple Player class for our example:

让我们先为我们的例子创建一个简单的Player类。

public class Player {
    private String firstName;
    private String lastName;
    private String position;

    // Standard getters/setters
}

3.1. Multiple Field Hashcode Implementation

3.1.多字段哈希码的实现

Let’s imagine that our Player class is considered unique across all three fields: firstName, lastName, and position.

让我们设想一下,我们的Player类被认为在所有三个字段中都是唯一的。firstName, lastName,position

With that said, let’s look at how we might have implemented Player.hashCode() prior to Java 7:

说到这里,让我们看看我们可能已经实现了 Player.hashCode(),在Java 7之前。

@Override
public int hashCode() {
    int result = 17;
    result = 31 * result + firstName != null ? firstName.hashCode() : 0;
    result = 31 * result + lastName != null ? lastName.hashCode() : 0;
    result = 31 * result + position != null ? position.hashCode() : 0;
    return result;
}

Because both Objects.hashCode() and Objects.hash() were introduced with Java 7, we have to explicitly check for null before calling Object.hashCode() on each field.

因为Objects.hashCode()Objects.hash()都是由Java 7引入的,我们必须在对每个字段调用Object.hashCode()之前明确检查null

Let’s confirm that we can both call hashCode() twice on the same object and get the same result and that we can call it on identical objects and get the same result:

让我们确认一下,我们既可以在同一个对象上调用hashCode()两次并得到相同的结果,也可以在相同的对象上调用它并得到相同的结果。

Player player = new Player("Eduardo", "Rodriguez", "Pitcher");
Player indenticalPlayer = new Player("Eduardo", "Rodriguez", "Pitcher");
        
int hashCode1 = player.hashCode();
int hashCode2 = player.hashCode();
int hashCode3 = indenticalPlayer.hashCode();
        
assertEquals(hashCode1, hashCode2);
assertEquals(hashCode1, hashCode3);

Next, let’s look at how we can shorten that a bit by taking advantage of null-safety we get with Objects.hashCode():

接下来,让我们看看如何通过利用Objects.hashCode()的空安全来缩短这个时间。

int result = 17;
result = 31 * result + Objects.hashCode(firstName);
result = 31 * result + Objects.hashCode(lastName);
result = 31 * result + Objects.hashCode(position);
return result;

If we run the same unit test, we should expect the same results.

如果我们运行相同的单元测试,我们应该期待相同的结果。

Because our class relies on multiple fields to determine equality, let’s go a step further and use Objects.hash() to make our hashCode() method very succinct:

因为我们的类依赖于多个字段来确定平等性,让我们更进一步,使用Objects.hash()来使我们的hashCode()方法非常简洁。

return Objects.hash(firstName, lastName, position);

After this update, we should be able to successfully run our unit test again.

经过这次更新,我们应该能够再次成功运行我们的单元测试。

3.2. Objects.hash() Details

3.2.Objects.hash()详情

Under the hood, when we call Objects.hash(), the values are placed in an array, and then Arrays.hashCode() is called on the array.

在引擎盖下,当我们调用Objects.hash()时,值被放在一个数组中,然后Arrays.hashCode()被调用到数组上。

With that said, let’s create a Player and compare its hashcode to Arrays.hashCode() with the values we use:

说到这里,让我们创建一个Player,并将其哈希代码与Arrays.hashCode()的值进行比较。

@Test
public void whenCallingHashCodeAndArraysHashCode_thenSameHashCodeReturned() {
    Player player = new Player("Bobby", "Dalbec", "First Base");
    int hashcode1 = player.hashCode();
    String[] playerInfo = {"Bobby", "Dalbec", "First Base"};
    int hashcode2 = Arrays.hashCode(playerInfo);
        
    assertEquals(hashcode1, hashcode2);
}

We created a Player and then created a String[]. Then we called hashCode() on the Player and used Arrays.hashCode() on the array and received the same hashcode.

我们创建了一个Player,然后创建了一个String[]。然后我们在Player上调用hashCode(),并在数组上使用Arrays.hashCode(),收到相同的哈希代码。

4. Conclusion

4.总结

In this article, we learned how and when to use the Object.hashCode(), Objects.hashCode() and Objects.hash(). Additionally, we looked into the differences between them.

在这篇文章中,我们了解了如何以及何时使用Object.hashCode()Objects.hashCode()Objects.hash()。此外,我们还研究了它们之间的区别。

As a review, let’s quickly summarize their usage:

作为回顾,让我们快速总结一下它们的用法。

  • Object.hashCode(): use to get the hashcode of a single, non-null object
  • Objects.hashCode(): use to get the hashcode of a single object that might be null
  • Objects.hash(): use to get a hashcode for multiple objects

As always, the example code is available over on GitHub.

像往常一样,示例代码可在GitHub上获得