Mengatasi kaedah equals() dan hashCode() dalam Java
Equals
dan hashCode
merupakan kaedah asas yang diisytiharkan dalam kelas Object
dan terkandung dalam perpustakaan Java standard. Kaedah ini еquals()
digunakan untuk membandingkan objek dan hashCode
menghasilkan kod integer untuk objek tersebut. Kaedah ini digunakan secara meluas dalam perpustakaan standard Java apabila memasukkan dan mendapatkan semula objek dalam HashMap
. Kaedah ini equal
juga digunakan untuk memastikan bahawa hanya objek unik disimpan dalam pelaksanaan HashSet
lain Set
, serta dalam mana-mana kes lain di mana objek perlu dibandingkan. Pelaksanaan lalai kaedah equals()
dalam kelas java.lang.Object
membandingkan rujukan kepada alamat memori yang disimpan oleh pembolehubah dan dikembalikan true
hanya jika alamat sepadan, dengan kata lain, pembolehubah merujuk kepada objek yang sama. Java mengesyorkan mengatasi kaedah equals()
dan hashCode()
jika anda menjangkakan perbandingan dilakukan mengikut logik semula jadi atau logik perniagaan. Banyak kelas dalam perpustakaan Java standard mengatasinya, contohnya kelas String
menimpa equals
supaya ia kembali true
jika kandungan dua objek yang dibandingkan adalah sama. Kelas pembalut mengatasi Integer
kaedah equal
untuk melakukan perbandingan berangka, dan seterusnya. Memandangkan Java HashMap
juga bergantung pada dan kaedah untuk membandingkan dan , Java menawarkan peraturan berikut untuk mengatasi kaedah ini: HashTable
equals()
hashCode()
key
values
- Reflekstiviti: Objek mestilah sama dengan dirinya sendiri.
- Simetri: jika
a.equals(b)
ia kembalitrue
, makab.equals(a)
ia juga mesti kembalitrue
. - Transitiviti: jika
a.equals(b)
ia kembalitrue
danb.equals(c)
juga kembalitrue
, makac.equals(a)
ia juga mesti kembalitrue
. - Ketekalan: Panggilan berulang kepada kaedah
equals()
mesti mengembalikan nilai yang sama selagi beberapa nilai sifat objek tidak diubah. Iaitu, jika dua objek sama di Jawa, maka ia akan sama selagi sifatnya tidak berubah. - Perbandingan
null
: Objek mesti diperiksa untuknull
. Jika objek adalah sama dengannull
, maka kaedah harus kembalifalse
, bukanNullPointerException
. Sebagai contoh,a.equals(null)
ia harus kembalifalse
.
Perjanjian antara equals dan hashCode dalam Java
- Jika objek adalah sama dalam hasil pelaksanaan kaedah
equals
, maka iahashcode
mestilah sama. - Jika objek tidak sama dalam hasil pelaksanaan kaedah
equals
, maka iahashcode
boleh sama ada sama atau berbeza. Walau bagaimanapun, untuk meningkatkan prestasi, adalah lebih baik untuk mempunyai objek yang berbeza mengembalikan kod yang berbeza.
Bagaimana untuk menimpa kaedah sama di Jawa
-
@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
dan kelas pembalut sepertiInteger
,Float
danDouble
mengatasi kaedahequals()
, tetapiStringBuffer
tidak mengatasi. -
Apabila boleh, buat medan
immutable
menggunakanfinal
pembolehubah dalam Java. -
Apabila membandingkan
String
objek, gunakanequals()
operator . sebaliknya==
. -
Dua objek yang secara logiknya sama tetapi dimuatkan daripada objek yang berbeza
ClassLoader
tidak boleh sama. Ingat bahawa menyemak dengangetClass()
akan kembalifalse
jika kelas pemuat adalah berbeza. -
Gunakan
@Override
anotasi juga pada kaedah .hashCode
, kerana ini menghalang ralat halus seperti nilai pulanganint
. Walau bagaimanapun, sesetengah pengaturcara mengembalikanlong
.
GO TO FULL VERSION