重寫 Java 中的 equals() 和 hashCode() 方法
Equals
和hashCode
是在類別中聲明Object
並包含在標準 Java 庫中的基本方法。 此方法еquals()
用於比較物件並hashCode
為物件產生整數程式碼。這些方法在 Java 標準庫中廣泛用於在HashMap
. 此方法equal
還用於確保在HashSet
其他Set
實作中以及需要比較物件的任何其他情況下僅儲存唯一物件。equals()
類別中該方法的預設實作java.lang.Object
會比較變數儲存的記憶體位址的引用,true
僅當位址匹配時才返回,換句話說,變數引用同一物件。如果您希望根據自然邏輯或業務邏輯進行比較,Java 建議重寫equals()
和方法。hashCode()
標準 Java 庫中的許多類別都會重寫它們,例如,類別String
會重寫equals
,以便true
在比較的兩個物件的內容相同時返回。包裝類別重寫Integer
方法equal
以執行數值比較等。由於JavaHashMap
也依賴和方法來比較它們的和,因此 Java 提供了以下規則來重寫這些方法: HashTable
equals()
hashCode()
key
values
- 自反性:對象必須等於其自身。
- 對稱:如果
a.equals(b)
它返回true
,那麼b.equals(a)
它也必須返回true
。 - 傳遞性:如果
a.equals(b)
它返回true
並且b.equals(c)
也返回true
,那麼c.equals(a)
它也必須返回true
。 equals()
一致性:只要物件的某些屬性值不會改變,重複呼叫一個方法就必須傳回相同的值。也就是說,如果兩個物件在Java中相等,那麼只要它們的屬性保持不變,它們就相等。- 比較
null
:必須檢查物件null
。如果該物件等於null
,則該方法應該返回false
,而不是NullPointerException
。例如,a.equals(null)
它應該返回false
.
Java中equals和hashCode的約定
- 如果方法執行結果相同
equals
,那麼它們hashcode
一定是相同的。 - 如果物件在方法執行的結果中不相等
equals
,那麼它們hashcode
可以相同也可以不同。但是,為了提高效能,最好讓不同的物件傳回不同的程式碼。
Как переопределять метод equals в Java
-
@Override public boolean equals(Object obj) { /*1. Check*/
if (obj == this) { /*and return */ return true; }
-
Проверьте an object на
null
, а также проверьте, чтобы an objectы были одного типа. Не делайте проверку с помощьюinstanceof
так How такая проверка будет возвращатьtrue
для подклассов и будет работать правильно только в случае если ваш класс объявлен Howimmutable
. Вместо этого можно использоватьgetClass()
;if (obj == null || obj.getClass() != this.getClass()) { return false; }
-
Объявите переменную типа, который вы сравниваете, и приведите
obj
к этому типу. Потом сравнивайте каждый атрибут типа начиная с численных атрибутов (если имеются) потому что численные атрибуты проверяются быстрей. Сравнивайте атрибуты с помощью операторов И и ИЛИ (так называемыеshort-circuit logical operators
) для объединения проверок с другими атрибутами.Person guest = (Person) obj; return id == guest.id && (firstName == guest.firstName || (firstName != null && firstName.equals(guest.getFirstName()))) && (lastName == guest.lastName || (lastName != null && lastName .equals(guest.getLastName()))); }
/** * Person class with equals and hashcode implementation in Java * @author Javin Paul */
public class Person {
private int id;
private String firstName;
private String lastName;
public int getId() { return id; }
public void setId(int id) { this.id = id;}
public String getFirstName() { return firstName; }
public void setFirstName(String firstName) { this.firstName = firstName; }
public String getLastName() { return lastName; }
public void setLastName(String lastName) { this.lastName = lastName; }
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null || obj.getClass() != this.getClass()) {
return false;
}
Person guest = (Person) obj;
return id == guest.id
&& (firstName == guest.firstName
|| (firstName != null &&firstName.equals(guest.getFirstName()))) && (lastName == guest.lastName
|| (lastName != null && lastName .equals(guest.getLastName())
));
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((firstName == null) ? 0 : firstName.hashCode()); result = prime * result + id; result = prime * result +
((lastName == null) ? 0 : lastName.hashCode()); return result;
}
}
Распространенные ошибки при переопределении equals в Java
-
Вместо того, чтобы переопределять метод
equals (Override)
программист перегружает его(Overload)
Синтаксис методаequals()
в классеObject
определен Howpublic boolean equals(Object obj)
, но многие программисты ненароком перегружают метод:public boolean equals(Person obj)
- instead ofObject
в качестве аргумента используют Name своего класса (напр. Person). Эту ошибку сложно обнаружить из-заstatic binding
. Таким образом, если вы вызовете этот метод для an object своего класса, то метод не просто скомпorруется, а даже сделает это корректно. Однако, если вы положите ваш an object в коллекцию, напримерArrayList
и вызовете методcontains()
, работа которого основана на методеequals()
, то методcontains
не сможет обнаружить ваш an object. -
При переопределении метода
equals()
не проверять наnull
переменные, что в конечном итоге заканчиваетсяNullPointerException
при вызовеequals()
. Ниже представлен корректный code.firstname == guest.firstname || (firstname != null && firstname.equals(guest.firstname));
-
Третья распространенная ошибка это не переопределять метод
hashCode()
, а толькоequals()
. Вы обязаны переопределять оба методаequals()
иhashCode()
в Java. МетодhashCode
используется вhash
-коллекциях(напримерHashSet
), и чем меньше будет коллизий (одинаковый code при разных an objectх) тем эффективнее эти коллекции будут работать с an objectми вашего класса. -
Последняя распространенная ошибка программистов в том, что при переопределении метода
equals()
не сохраняется соответствие между методамиequals()
иcompareTo()
, что является неформальным требованием для избежания хранения дубликатов вSet (SortedSet, TreeSet)
.
Подсказки How писать в Java метод equals
-
Большинство IDE такие How NetBeans, Eclipse и IntelliJ IDEA обеспечивают поддержку генерации методов
equals()
иhashCode()
. В Eclipse нажмите правую кнопку -> source ->generate equals()
иhashCode()
. -
Если в классе есть уникальный бизнес-ключ, то будет достаточно сделать проверку только на equalsство этих полей. Как в нашем примере “id” - уникальный номер для каждого Person.
-
При переопределении
hashCode()
в Java удостоверьтесь в использовании всех полей, что были использованы в методеequals()
. -
String
和包裝類別等Integer
,Float
並Double
重寫方法equals()
,但StringBuffer
不重寫。 -
只要有可能,在 Java 中
immutable
使用final
變數來建立欄位。 -
比較
String
物件時,請使用equals()
. 運算子==
。 -
邏輯上相等但從不同物件載入的兩個物件
ClassLoader
不能相等。請記住,如果載入器類別不同,則檢查getClass()
將返回。false
-
在 . 方法上也使用
@Override
註釋hashCode
,因為這可以防止微妙的錯誤,例如 . 的返回值int
。但是,有些程式設計師會回傳long
.
GO TO FULL VERSION