Javaコレクション– hashCode()およびequals()– Javaでequals()およびhashcode()メソッドをオーバーライドする方法は?
公開: 2018-08-08
Javaのequals()
とhashCode()
は、Objectクラスと一部またはコアのJavaライブラリで宣言される2つの基本的なメソッドです。
Javaで以下の懸念事項のいずれかがある場合は、適切な場所にいます。
- Javaプラクティス-> equalsの実装
- オーバーライド–JavaでのequalsとhashCodeのオーバーライド
- Javaでequals()メソッドをオーバーライドする方法
- JavaでhashCode()メソッドをオーバーライドする方法
- JavaでequalsおよびhashCodeメソッドをオーバーライドする方法
- Javaでequalsメソッドをオーバーライドする方法と理由
- equals()をオーバーライドする場合、なぜ常にhashcode()をオーバーライドするのですか?
最初のReference Equality
とLogical Equality
を理解するための簡単な例を見てみましょう。 等式演算子(==)は、2つの文字列の参照(メモリ内のアドレス)を2つの異なる数値として比較します。これはReference equality
として知られています。
Logical equality
は、参照の値ではなく、オブジェクトのデータを比較します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
package com . crunchify . tutorials ; /** * @author Crunchify.com */ public class CrunchifyLogicalVsReferenceEqality { public static void main ( String [ ] args ) { String strA = new String ( "eBay" ) ; String strB = new String ( "eBay" ) ; String strC = new String ( "Paypal" ) ; // Create a String reference and assign an existing String's reference to it // so that both references point to the same String object in memory. String strD = strA ; // Print out the results of various equality checks // Reference Equality System . out . println ( "Reference Equality Result:" ) ; System . out . println ( strA == strB ) ; System . out . println ( strA == strC ) ; System . out . println ( strA == strD ) ; // Logical Equality System . out . println ( "\nLogical Equality Result:" ) ; System . out . println ( strA . equals ( strB ) ) ; System . out . println ( strA . equals ( strC ) ) ; System . out . println ( strA . equals ( strD ) ) ; } } |
出力:
1 2 3 4 5 6 7 8 9 |
Reference Equality Result : false false true Logical Equality Result : true false true |
hashCodeとequalsは密接に関連しています:
- equalsをオーバーライドする場合は、 hashCodeをオーバーライドする必要があります。
- hashCodeは、等しいオブジェクトに対して等しい値を生成する必要があります。
- equalsおよびhashCodeは
same set of significant fields
依存する必要があります。 これらの方法の両方で同じフィールドのセットを使用する必要があります。 すべてのフィールドを使用する必要はありません。 たとえば、他に依存する計算フィールドは、equals
およびhashCode
から省略される可能性が非常に高くなります。
equalsを実装する場合、フィールドはタイプに応じて異なる方法で比較されます。
- コレクションを含むオブジェクトフィールド: equalsを使用
- タイプセーフな列挙: equalsまたは==のいずれかを使用します(この場合、同じものになります)
- nullの可能性のあるオブジェクトフィールド: ==とequalsの両方を使用
- 配列フィールド:
Arrays.equals
を使用します - floatまたはdouble以外のプリミティブフィールド:use ==
-
float
:を使用してintに変換しますFloat.floatToIntBits ,
次に==を使用します double
:Double.doubleToLongBits
を使用してlongに変換し、次に==を使用します
hashCodeの実装:
- クラスがequalsをオーバーライドする場合、 hashCodeをオーバーライドする必要があります
- 両方がオーバーライドされる場合、 equalsとhashCodeは同じフィールドのセットを使用する必要があります
- 2つのオブジェクトが等しい場合、それらのhashCode値も等しくなければなりません
- オブジェクトが不変である場合、 hashCodeはキャッシングと遅延初期化の候補です
hashCodeがオブジェクトの一意の識別子を提供するというのはよくある誤解です。 そうではありません。
一般的な契約により、Javaのequals()
メソッドは、再帰的、対称的、推移的、一貫性があり、null以外の参照はfalseを返す必要があります。 つまり、a、b、およびcの任意の値について、次のテストは常に合格する必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/ reflexive property assertTrue ( a . equals ( a ) ) ; // symmetric property assertTrue ( a . equals ( b ) == b . equals ( a ) ) ; // transitive property if ( a . equals ( b ) && b.equals(c) ) { assertTrue( a.equals(c) ); } // consistency property assertTrue ( a . equals ( b ) == a . equals ( b ) ) ; // non-null property assertFalse ( a . equals ( null ) ) ; |
ベストプラクティスについては、以下の手順を使用して、equals()メソッドを実装します。
- これを使用して==参照の同等性をチェックします
instanceof
を使用して、正しい引数タイプをテストします- 引数を正しい型にキャストします
- 重要なフィールドを比較して同等性を確認する
これが完全な例です。
CrunchifyImplementEqualsHashCode.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
package crunchify . com . tutorials ; /** * * @author Crunchify.com * How to Override equals() method in Java? * How to Override hasCode() method in Java? * version:1.2 * */ public class CrunchifyImplementEqualsHashCode { public static void main ( String [ ] args ) { CrunchifyImplementEqualsHashCode crunchifyTest = new CrunchifyImplementEqualsHashCode ( ) ; Crunchify one = new Crunchify ( 1 ) ; Crunchify two = new Crunchify ( 1 ) ; crunchifyTest . test1 ( one , two ) ; Crunchify three = new Crunchify ( 1 ) ; Crunchify four = new Crunchify ( 2 ) ; crunchifyTest . test2 ( three , four ) ; } public void test1 ( Crunchify one , Crunchify two ) { if ( one . equals ( two ) ) { System . out . println ( "Test1: One and Two are equal" ) ; } else { System . out . println ( "Test1: One and Two are not equal" ) ; } } public void test2 ( Crunchify three , Crunchify four ) { if ( three . equals ( four ) ) { System . out . println ( "Test2: Three and Four are equal" ) ; } else { System . out . println ( "Test2: Three and Four are not equal" ) ; } } } class Crunchify { private int value ; Crunchify ( int val ) { value = val ; } public int getValue ( ) { return value ; } // The method does override or implement a method declared in a supertype. @Override public boolean equals ( Object o ) { // null check if ( o == null ) { return false ; } // this instance check if ( this == o ) { return true ; } // instanceof Check and actual value check if ( ( o instanceof Crunchify ) && (((Crunchify) o).getValue() == this.value)) { return true; } else { return false ; } } @Override public int hashCode ( ) { int result = 0 ; result = ( int ) ( value / 11 ) ; return result ; } } |
Eclipseコンソールの出力:
1 2 |
Test1 : One and Two are equal Test2 : Three and Four are not equal |