Javaにおけるequals()メソッドとhashCode()メソッドの契約(コントラクト)とは?
すべてのJavaオブジェクトはequals()とhashCode()という非常に重要な2つのメソッドを持っており、これらはそれぞれ定められた一般契約(General Contract)に従ってオーバーライドされることが想定されています。Objectクラスはすべてのクラスの親クラスであるため、この2つのメソッドのデフォルト実装はすべてのクラスに最初から存在します。ただし、必要に応じてこれらのメソッドをオーバーライドすることが可能です。
hashCode()メソッドとは
public int hashCode()
このメソッドはint型(整数値)を返し、その値はオブジェクトのハッシュコード値と呼ばれます。すべてのオブジェクトは生成時に、一意な32ビット符号付きint値が割り当てられます。この値がそのオブジェクトのハッシュコード値となります。
hashCode()メソッドに関連する一般契約
- hashCode()メソッドは、オブジェクト内部の値が変更されない限り、同じオブジェクトに対して呼び出すたびに同じ整数値を返さなければなりません。
- equals()メソッドによって等しいと判定された2つのオブジェクトの場合、hashCode()メソッドは両方のオブジェクトに対して同じ整数値を返す必要があります。
- ただし、equals()メソッドで等しくないと判定されたオブジェクトに対して、hashCode()メソッドが必ず異なる値を返す必要はありません。
equals()メソッドとは
public boolean equals(Object obj)
Objectクラスのequals()メソッドはオブジェクト同士の等価性をチェックし、その結果に応じてtrueまたはfalseを返します。Objectクラスが提供するデフォルト実装では、両方の参照が同一のオブジェクトを指しているかどうかのみを比較します。つまり、オブジェクトの値や状態までは確認しません。しかし、このメソッドをオーバーライドすることで、オブジェクトの状態や値を比較する独自の実装を提供できます。
equals()メソッドに関連する一般契約
null以外の任意の参照変数a、b、cに対して、以下が成り立ちます。
- 反射性:a.equals(a)は常にtrueを返す必要があります。
- 対称性:b.equals(a)がtrueを返す場合、かつその場合に限り、a.equals(b)もtrueを返す必要があります。
- 推移性:a.equals(b)がtrueを返し、かつb.equals(c)がtrueを返すならば、a.equals(c)もtrueを返す必要があります。
- 一貫性:いずれのオブジェクトの値も変更されていない限り、a.equals(b)を複数回呼び出した結果は、常にtrue、または常にfalseで一貫していなければなりません。
- nullとの比較:a.equals(null)はfalseを返す必要があります。
したがって、equals()メソッドをオーバーライドする場合は、ObjectクラスのhashCode()メソッドも必ず一緒にオーバーライドしなければなりません。これは、HashMapやHashSetなどのハッシュベースのコレクションを正しく動作させるために不可欠です。
実装例
public class MainClass {
public static void main(String[] args) {
MainClass mainClass = new MainClass();
TestClass obj1 = new TestClass(1);
TestClass obj2 = new TestClass(1);
mainClass.test1(obj1, obj2);
TestClass obj3 = new TestClass(1);
TestClass obj4 = new TestClass(2);
mainClass.test2(obj3, obj4);
}
public void test1(TestClass obj1, TestClass obj2) {
if (obj1.equals(obj2)) {
System.out.println("Object One and Object Two are equal");
}
else {
System.out.println("Object One and Object Two are not equal");
}
}
public void test2(TestClass obj3, TestClass obj4) {
if (obj3.equals(obj4)) {
System.out.println("Object Three and Object Four are equal");
}
else {
System.out.println("Object Three and Object Four are not equal");
}
}
}
class TestClass {
private int val;
TestClass(int val) {
this.val = val;
}
public int getValue() {
return val;
}
@Override
public boolean equals(Object o) {
// nullチェック
if (o == null) {
return false;
}
// 自身のインスタンスかどうかのチェック
if (this == o) {
return true;
}
// instanceofチェックと実際の値のチェック
if ((o instanceof TestClass) && (((TestClass) o).getValue() == this.val)) {
return true;
}
else {
return false;
}
}
@Override
public int hashCode() {
int result = 0;
result = (int) (val / 11);
return result;
}
}
実行結果
Object One and Object Two are equal
Object Three and Object Four are not equal
この例では、TestClassクラスでequals()メソッドをオーバーライドし、フィールド「val」の値に基づいて等価性を判断しています。obj1とobj2は同じ値(1)を持つため等しいと判定され、obj3(値:1)とobj4(値:2)は異なる値を持つため等しくないと判定されます。また、hashCode()メソッドもvalの値から計算されるハッシュコードを返すようにオーバーライドされており、equals()との契約が守られています。
-
JREとJDKの違いは何?Java開発初心者向けにわかりやすく解説
Javaを学び始めると、必ず耳にするのが「JDK」と「JRE」という2つの用語です。名前が似ているため混同されやすいのですが、それぞれ役割や含まれる機能が異なります。この記事では、両者の違いを初心者にもわかりやすく解説します。 JDK(Java Development Kit)とは JDKは「Java Development Kit」の略で、Javaアプリケーションの開発と実行に必要なすべてのツールおよびライブラリをまとめたソフトウェアパッケージです。 JDKには以下のようなものが含まれています。 コンパイラ(javac):ソースコード(.javaファイル)をバイトコード(.classファイ
-
JavaとJavaScriptの違いとは?歴史・技術・使い分けを徹底解説
ウェブ開発者のジェレミー・キースは2009年、「JavaとJavaScriptの関係は、ハムとハムスターの関係のようなものだ」と語りました。この比喩がどれほど正確かは議論の余地がありますが、その本質は的確です。共通する言語的ルーツを持つにもかかわらず、JavaとJavaScriptはまったく異なる2つのプログラミング言語なのです。年月とともに両者の重なりも多少増えましたが、今なおJavaScriptはウェブサイトにインタラクティブ性をもたらすフロントエンド言語の主流であり続け、Javaはサーバーサイドやアプリケーション開発で人気を保っています。開発者を採用したい方、プログラミングを学びたい方