Java Collections – hashCode() 和 equals() – 如何在 Java 中覆蓋 equals() 和 hashcode() 方法?
已發表: 2018-08-08
Java 中的equals()
和hashCode()
是在 Object 類和部分或核心 Java 庫中聲明的兩個基本方法。
如果您在 Java 中有以下任何問題,那麼您來對地方了。
- Java 實踐 -> 實現 equals
- override – 在 Java 中覆蓋 equals 和 hashCode
- 如何在java中覆蓋equals()方法
- 如何在java中覆蓋hashCode()方法
- 如何在 Java 中覆蓋 equals 和 hashCode 方法
- 如何以及為什麼在 Java 中重寫 equals 方法
- 如果覆蓋 equals(),為什麼總是覆蓋 hashcode()?
讓我們看一個簡單的例子來了解第一個Reference Equality
和Logical Equality
。 相等運算符 (==) 將兩個字符串的引用(內存中的地址)作為兩個不同的數字進行比較——這稱為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或== (在這種情況下,它們等同於相同的東西)
- 可能為空的對象字段:同時使用==和equals
- 數組字段:使用
Arrays.equals
- float或double以外的原始字段:使用==
-
float
: 轉換為int使用Float.floatToIntBits ,
然後使用== -
double
:使用Double.doubleToLongBits
轉換為long ,然後使用==
實現hashCode :
- 如果一個類覆蓋了equals ,它必須覆蓋hashCode
- 當它們都被覆蓋時, equals和hashCode必須使用相同的字段集
- 如果兩個對象相等,那麼它們的hashCode值也必須相等
- 如果對像是不可變的,則hashCode是緩存和延遲初始化的候選對象
hashCode為對象提供唯一標識符是一種流行的誤解。 它不是。
按照一般約定,Java 中的equals()
方法必須是自反的、對稱的、傳遞的、一致的,並且任何非空引用都必須返回 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() 方法:
- 使用 this == that 來檢查引用相等
- 使用
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 |