Коллекции Java – hashCode() и equals() – Как переопределить методы equals() и hashcode() в Java?
Опубликовано: 2018-08-08
equals()
и hashCode()
в Java — это два фундаментальных метода, которые объявлены в классе Object и частично или в основной библиотеке Java.
Если у вас есть какие-либо из перечисленных ниже проблем в Java, то вы попали по адресу.
- Практика Java -> Реализация равных
- override — переопределение equals и hashCode в Java
- Как переопределить метод equals() в java
- Как переопределить метод hashCode() в java
- Как переопределить метод equals и hashCode в Java
- Как и зачем переопределять метод equals в Java
- Зачем всегда переопределять hashcode(), если переопределяется equals()?
Давайте рассмотрим простой пример, чтобы понять первое 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
: преобразовать в long с помощьюDouble.doubleToLongBits
, затем использовать ==
Реализация хэш-кода :
- если класс переопределяет equals , он должен переопределять hashCode
- когда они оба переопределены, equals и hashCode должны использовать один и тот же набор полей
- если два объекта равны, то их значения hashCode также должны быть равны
- если объект неизменяем, то hashCode является кандидатом на кеширование и ленивую инициализацию
Это популярное заблуждение, что hashCode предоставляет уникальный идентификатор для объекта. Это не.
Согласно общему соглашению, метод equals()
в Java должен быть рефлексивным, симметричным, транзитивным, непротиворечивым, и любая ненулевая ссылка должна возвращать 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 |