Saat membandingkan objek di Java, Anda melakukan pemeriksaan semantik , membandingkan tipe dan status identifikasi objek ke:
- sendiri (contoh yang sama)
- itu sendiri (kloning, atau salinan yang direkonstruksi)
- objek lain dari jenis yang berbeda
- objek lain dengan tipe yang sama
null
Aturan:
- Simetri :
a.equals(b) == b.equals(a)
equals()
selalu menghasilkan true
atau false
, tapi tidak pernah NullpointerException
, ClassCastException
atau lemparan lainnya
Perbandingan:
- Jenis pemeriksaan : kedua contoh harus berjenis sama , artinya Anda harus membandingkan kelas aktual untuk kesetaraan. Ini sering tidak diterapkan dengan benar, ketika pengembang menggunakan
instanceof
untuk perbandingan tipe (yang hanya berfungsi selama tidak ada subkelas, dan melanggar aturan simetri ketika A extends B -> a instanceof b != b instanceof a)
.
- Pemeriksaan semantik dari status pengidentifikasi : Pastikan Anda memahami dengan status mana instance diidentifikasi. Orang dapat dikenali dari nomor jaminan sosialnya, tetapi tidak berdasarkan warna rambut (dapat diwarnai), nama (dapat diubah) atau usia (berubah-ubah setiap saat). Hanya dengan objek nilai Anda harus membandingkan status lengkap (semua bidang non-sementara), jika tidak, centang hanya apa yang mengidentifikasi instance.
Untuk Person
kelas Anda :
public boolean equals(Object obj) {
// same instance
if (obj == this) {
return true;
}
// null
if (obj == null) {
return false;
}
// type
if (!getClass().equals(obj.getClass())) {
return false;
}
// cast and compare state
Person other = (Person) obj;
return Objects.equals(name, other.name) && Objects.equals(age, other.age);
}
Kelas utilitas umum yang dapat digunakan kembali:
public final class Equals {
private Equals() {
// private constructor, no instances allowed
}
/**
* Convenience equals implementation, does the object equality, null and type checking, and comparison of the identifying state
*
* @param instance object instance (where the equals() is implemented)
* @param other other instance to compare to
* @param stateAccessors stateAccessors for state to compare, optional
* @param <T> instance type
* @return true when equals, false otherwise
*/
public static <T> boolean as(T instance, Object other, Function<? super T, Object>... stateAccessors) {
if (instance == null) {
return other == null;
}
if (instance == other) {
return true;
}
if (other == null) {
return false;
}
if (!instance.getClass().equals(other.getClass())) {
return false;
}
if (stateAccessors == null) {
return true;
}
return Stream.of(stateAccessors).allMatch(s -> Objects.equals(s.apply(instance), s.apply((T) other)));
}
}
Untuk Person
kelas Anda , menggunakan kelas utilitas ini:
public boolean equals(Object obj) {
return Equals.as(this, obj, t -> t.name, t -> t.age);
}