1. 序章

ハッシュコードは、オブジェクトの内容を数値で表したものです。

Javaでは、オブジェクトのハッシュコードを取得するために使用できるいくつかの異なるメソッドがあります。

  • Object.hashCode() 
  • Objects.hashCode()– Java7で導入
  • Objects.hash() –Java7で導入

このチュートリアルでは、これらの各メソッドを見ていきます。 まず、定義と基本的な例から始めます。 基本的な使用法を理解した後、それらの違いと、それらの違いがもたらす可能性のある影響について掘り下げていきます。

2. 基本的な使用法

2.1. Object.hashCode()

Object.hashCode()メソッドを使用して、オブジェクトのハッシュコードを取得できます。 Objects.hashCode()と非常によく似ていますが、オブジェクトがnullの場合は使用できない点が異なります。

そうは言っても、2つの同一の 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);

予想どおり、同じハッシュコードを受け取ります。

対照的に、 NullPointerException がスローされることを期待して、 nullオブジェクトでObject.hashCode()を呼び出しましょう。

Double value = null;
value.hashCode();

2.2. Objects.hashCode()

Objects.hashCode()は、オブジェクトのhashcodeを取得するために使用できるnullセーフメソッドです。 ハッシュコードは、ハッシュテーブルと equals()の適切な実装に必要です。

JavaDocで指定されているハッシュコードの一般的なコントラクトは次のとおりです。

  • 返される整数は、アプリケーションの同じ実行中に変更されていないオブジェクトが呼び出されるたびに同じになります
  • equals()メソッドに従って等しい2つのオブジェクトの場合、同じハッシュコードを返します

必須ではありませんが、個別のオブジェクトは可能な限り異なるハッシュコードを返します。

まず、2つの同一の文字列に対して Objects.hashCode()を呼び出しましょう。

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

ここで、返されるハッシュコードは同一であると予想されます。

一方、 nullObjects.hashCode()に指定すると、ゼロが返されます。

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

2.3. Objects.hash()

Objects.hashCode()とは異なり、は単一のオブジェクトのみを取得しますが、 Objects.hash()は1つ以上のオブジェクトを取得し、それらにハッシュコードを提供します。 内部的には、 hash()メソッドは、提供されたオブジェクトを配列に入れ、それらに対して Arrays.hashCode()を呼び出すことによって機能します。オブジェクトを1つだけ提供する場合Objects.hash()メソッドの場合、オブジェクトでObjects.hashCode()を呼び出すのと同じ結果を期待することはできません。

まず、同じ文字列の2つのペアを使用して 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);

次に、 Objects.hash() Objects.hashCode()を1つの文字列で呼び出します。

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

予想どおり、返された2つのハッシュコードは一致しません。

3. 主な違い

前のセクションでは、 Objects.hash() Objects.hashCode()の主な違いについて説明しました。 それでは、いくつかの影響を理解できるように、もう少し深く掘り下げてみましょう。

クラスのequals()メソッドのいずれかをオーバーライドする必要がある場合は、 hashCode()も適切にオーバーライドすることが重要です。

この例では、単純なPlayerクラスを作成することから始めましょう。

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

    // Standard getters/setters
}

3.1. 複数フィールドのハッシュコードの実装

Player クラスが、 firstName lastName、positionの3つのフィールドすべてで一意であると見なされると想像してみてください。

そうは言っても、Java7より前にどのように Player.hashCode()を実装したかを見てみましょう。

@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;
}

Objects.hashCode() Objects.hash()の両方がJava 7で導入されたため、Objectを呼び出す前にnullを明示的にチェックする必要があります各フィールドの.hashCode()

同じオブジェクトでhashCode()を2回呼び出して同じ結果を得ることができ、同じオブジェクトで同じ結果を得ることができることを確認しましょう。

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);

次に、 Objects.hashCode()で得られるnullの安全性を利用して、これを少し短縮する方法を見てみましょう。

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

同じ単体テストを実行すると、同じ結果が期待できます。

このクラスは複数のフィールドに依存して同等性を判断するため、さらに一歩進んで Objects.hash()を使用して、 hashCode()メソッドを非常に簡潔にします。

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

この更新後、単体テストを再度正常に実行できるようになります。

3.2. Objects.hash()詳細

内部的には、 Objects.hash()を呼び出すと、値が配列に配置され、 Arrays.hashCode()が配列で呼び出されます。

それでは、 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);
}

作成しましたプレーヤーその後、作成しました弦[]。 それから私たちは電話しましたハッシュコード()プレーヤー使用済み Arrays.hashCode() 配列上で同じハッシュコードを受け取りました。

4. 結論

この記事では、 Object.hashCode() Objects.hashCode()、および Objects.hash()をいつどのように使用するかを学びました。 さらに、それらの違いを調べました。

レビューとして、それらの使用法を簡単に要約しましょう。

  • Object.hashCode():単一のnull以外のオブジェクトのハッシュコードを取得するために使用します
  • Objects.hashCode():nullの可能性がある単一のオブジェクトのハッシュコードを取得するために使用します
  • Objects.hash():複数のオブジェクトのハッシュコードを取得するために使用します

いつものように、サンプルコードはGitHubから入手できます。