Java Challengers # 4: Membandingkan objek dengan equals () dan hashCode ()
Untuk mengantisipasi peluncuran utas baru pada kursus "Pengembang Java", kami terus menerjemahkan serangkaian artikel Java Challengers, yang sebelumnya dapat dibaca di tautan di bawah:
Ayo pergi!
Dalam artikel ini, Anda akan belajar bagaimana metode equals()
dan hashCode()
saling terkait dan bagaimana mereka digunakan saat membandingkan objek.

Tanpa menggunakan equals()
dan hashCode()
untuk membandingkan keadaan dua objek, kita perlu menulis banyak perbandingan " if
" membandingkan setiap bidang objek. Pendekatan ini membuat kode membingungkan dan sulit dibaca. Bekerja bersama, kedua metode ini membantu menciptakan kode yang lebih fleksibel dan konsisten.
Kode sumber untuk artikel ada di sini .
Mengganti equals () dan hashCode ()
Metode overriding adalah teknik di mana perilaku kelas induk atau antarmuka ditulis ulang (didefinisikan ulang) dalam subkelas (lihat Java Challengers # 3: Polymorphism and Inheritance , Eng. ). Di Jawa, setiap objek memiliki metode equals()
dan hashCode()
, dan agar berfungsi dengan baik, mereka harus diganti.
Untuk memahami bagaimana redefinisi equals()
dan hashCode()
bekerja, mari kita periksa implementasinya di kelas dasar Java. Berikut ini adalah metode equals()
dari kelas Object
. Metode ini memeriksa apakah instance saat ini cocok dengan objek obj
berlalu.
public boolean equals(Object obj) { return (this == obj); }
Sekarang mari kita lihat metode hashCode()
di kelas Object
.
@HotSpotIntrinsicCandidate public native int hashCode();
Ini asli - metode yang ditulis dalam bahasa lain, seperti C, dan mengembalikan beberapa kode numerik yang terkait dengan alamat memori objek. (Jika Anda tidak menulis kode JDK, tidak penting untuk mengetahui dengan tepat cara kerja metode ini.)
Catatan Penerjemah: nilai yang terkait dengan alamat tidak sepenuhnya benar ( terima kasih kepada vladimir_dolzhenko ). HotSpot JVM menggunakan nomor acak semu secara default. Deskripsi implementasi hashCode () untuk HotSpot ada di sini dan di sini .
Jika metode equals()
dan hashCode()
tidak diganti, metode kelas Object
dijelaskan di atas akan dipanggil sebagai gantinya. Dalam hal ini, metode tidak memenuhi tujuan sebenarnya dari equals()
dan hashCode()
, yang untuk memeriksa apakah objek memiliki keadaan yang sama.
Biasanya, menimpa equals()
juga menimpa hashCode()
.
Membandingkan objek dengan equals ()
Metode equals()
digunakan untuk membandingkan objek. Untuk menentukan apakah objek identik atau tidak, equals()
membandingkan nilai bidang objek:
public class EqualsAndHashCodeExample { public static void main(String... args){ System.out.println(new Simpson("Homer", 35, 120) .equals(new Simpson("Homer",35,120))); System.out.println(new Simpson("Bart", 10, 120) .equals(new Simpson("El Barto", 10, 45))); System.out.println(new Simpson("Lisa", 54, 60) .equals(new Object())); } static class Simpson { private String name; private int age; private int weight; public Simpson(String name, int age, int weight) { this.name = name; this.age = age; this.weight = weight; } @Override public boolean equals(Object o) {
Mari kita lihat metode equals()
. Perbandingan pertama membandingkan contoh saat this
dengan yang disahkan o
. Jika itu adalah objek yang sama, maka equals()
akan mengembalikan true
.
Perbandingan kedua memeriksa untuk melihat apakah objek yang dikirimkan adalah null
dan apa jenisnya. Jika objek yang ditransfer adalah tipe yang berbeda, maka objek tidak sama.
Akhirnya, equals()
membandingkan bidang objek. Jika dua objek memiliki nilai bidang yang sama, maka objeknya sama.
Analisis opsi untuk membandingkan objek
Sekarang mari kita lihat opsi untuk membandingkan objek dalam metode main()
. Pertama, kami membandingkan dua objek Simpson
:
System.out.println( new Simpson("Homer", 35, 120).equals( new Simpson("Homer", 35, 120)));
Bidang objek ini memiliki nilai yang sama, sehingga hasilnya akan true
.
Kemudian lagi membandingkan dua objek Simpson
:
System.out.println( new Simpson("Bart", 10, 45).equals( new Simpson("El Barto", 10, 45)));
Objek di sini mirip, tetapi arti nama-nama itu berbeda: Bart dan El Barto . Karena itu, hasilnya akan false
.
Akhirnya, mari kita bandingkan objek Simpson
dan instance dari kelas Object
:
System.out.println( new Simpson("Lisa", 54, 60).equals( new Object()));
Dalam hal ini, hasilnya akan false
, karena jenis objeknya berbeda.
sama dengan () versus ==
Pada pandangan pertama, tampaknya operator ==
dan equals()
melakukan hal yang sama, tetapi pada kenyataannya, mereka bekerja secara berbeda. Operator ==
membandingkan apakah dua tautan menunjuk ke objek yang sama. Sebagai contoh:
Simpson homer = new Simpson("Homer", 35, 120); Simpson homer2 = new Simpson("Homer", 35, 120); System.out.println(homer == homer2);
Kami membuat dua contoh berbeda dari Simpson
menggunakan operator new
. Oleh karena itu, variabel homer
dan homer2
akan menunjuk ke objek yang berbeda di heap . Jadi, sebagai hasilnya, kita false
.
Dalam contoh berikut, kami menggunakan metode equals()
ditimpa:
System.out.println(homer.equals(homer2));
Dalam hal ini, bidang akan dibandingkan. Karena kedua objek Simpson
memiliki nilai bidang yang sama, hasilnya akan true
.
Identifikasi objek dengan kode hash ()
Untuk mengoptimalkan kinerja saat membandingkan objek, metode hashCode()
digunakan. Metode hashCode()
mengembalikan pengidentifikasi unik untuk setiap objek, yang menyederhanakan perbandingan status objek.
Jika kode hash suatu objek tidak cocok dengan kode hash objek lain, maka Anda dapat menghilangkan metode equals()
: Anda hanya tahu bahwa dua objek tidak cocok. Di sisi lain, jika kode hash sama maka Anda harus menjalankan metode equals()
untuk menentukan apakah nilai bidang cocok.
Pertimbangkan contoh praktis dengan hashCode()
.
public class HashcodeConcept { public static void main(String... args) { Simpson homer = new Simpson(1, "Homer"); Simpson bart = new Simpson(2, "Homer"); boolean isHashcodeEquals = homer.hashCode() == bart.hashCode(); if (isHashcodeEquals) { System.out.println(" equals."); } else { System.out.println(" equals, .. " + " , , ."); } } static class Simpson { int id; String name; public Simpson(int id, String name) { this.id = id; this.name = name; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Simpson simpson = (Simpson) o; return id == simpson.id && name.equals(simpson.name); } @Override public int hashCode() { return id; } } }
Metode hashCode()
, yang selalu mengembalikan nilai yang sama, valid tetapi tidak efisien. Dalam hal ini, perbandingan akan selalu mengembalikan true
, sehingga metode equals()
akan selalu dieksekusi. Dalam hal ini, tidak ada peningkatan kinerja.
Menggunakan equals () dan hashCode () dengan koleksi
Kelas yang mengimplementasikan Set
interface (set) harus mencegah elemen duplikat dari ditambahkan. Di bawah ini adalah beberapa kelas yang mengimplementasikan antarmuka Set
:
Hanya elemen unik yang dapat ditambahkan ke Set
. Jadi, jika Anda ingin menambahkan elemen, misalnya, ke HashSet
, Anda harus terlebih dahulu menggunakan metode equals()
dan hashCode()
untuk memastikan bahwa elemen ini unik. Jika metode equals()
dan hashCode()
belum diganti, Anda berisiko memasukkan nilai duplikat.
Mari kita lihat bagian implementasi dari metode add()
di HashSet
:
if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e;
Sebelum menambahkan item baru, HashSet
memeriksa untuk melihat apakah item tersebut ada dalam koleksi ini. Jika objek cocok, maka elemen baru tidak akan dimasukkan.
Metode equals()
dan hashCode()
digunakan tidak hanya di Set
. Metode ini juga diperlukan untuk HashMap , Hashtable , dan LinkedHashMap . Sebagai aturan, jika Anda melihat koleksi dengan awalan "Hash" , Anda dapat memastikan bahwa untuk operasinya yang benar diperlukan penggantian kode hashCode()
dan equals()
.
Rekomendasi untuk menggunakan equals () dan hashCode ()
Jalankan metode equals()
hanya untuk objek dengan kode hash yang sama. Jangan jalankan equals()
jika kode hash berbeda.
Tabel 1. Perbandingan Kode Hash
Jika perbandingan hashCode () ... | Itu ... |
---|
mengembalikan true | jalankan equals() |
mengembalikan false | jangan jalankan equals() |
Prinsip ini terutama digunakan dalam koleksi Set
atau Hash
untuk alasan kinerja.
Aturan perbandingan objek
Ketika perbandingan kode hashCode()
mengembalikan false
, metode equals()
juga harus mengembalikan false
. Jika kode hash berbeda, maka objek pasti tidak sama.
Tabel 2. Perbandingan objek dengan kode hash ()
Ketika perbandingan kode hashCode() mengembalikan ... | Metode equals() harus mengembalikan ... |
---|
true | true atau false |
false | false |
Ketika metode equals()
mengembalikan true
, ini berarti bahwa objek sama dalam semua nilai dan atribut . Dalam hal ini, perbandingan kode hash juga harus benar.
Tabel 3. Perbandingan objek dengan equals ()
Ketika metode equals() mengembalikan ... | Metode hashCode() harus mengembalikan ... |
---|
true | true |
false | true atau false |
Memecahkan masalah pada equals () dan hashCode ()
Saatnya untuk menguji pengetahuan Anda tentang equals()
dan metode hashCode()
. Tugasnya adalah untuk mengetahui hasil beberapa equals()
dan ukuran total koleksi Set
.
Untuk memulai, pelajari kode berikut dengan cermat:
public class EqualsHashCodeChallenge { public static void main(String... args) { System.out.println(new Simpson("Bart").equals(new Simpson("Bart"))); Simpson overriddenHomer = new Simpson("Homer") { public int hashCode() { return (43 + 777) + 1; } }; System.out.println(new Simpson("Homer").equals(overriddenHomer)); Set set = new HashSet(Set.of(new Simpson("Homer"), new Simpson("Marge"))); set.add(new Simpson("Homer")); set.add(overriddenHomer); System.out.println(set.size()); } static class Simpson { String name; Simpson(String name) { this.name = name; } @Override public boolean equals(Object obj) { Simpson otherSimpson = (Simpson) obj; return this.name.equals(otherSimpson.name) && this.hashCode() == otherSimpson.hashCode(); } @Override public int hashCode() { return (43 + 777); } } }
Pertama, menganalisis kode, pikirkan tentang apa hasilnya nanti. Dan baru kemudian menjalankan kode. Tujuannya adalah untuk meningkatkan keterampilan analisis kode Anda dan mempelajari konsep-konsep dasar Java sehingga Anda dapat membuat kode Anda lebih baik.
Apa hasilnya?
A) true true 4 B) true false 3 C) true false 2 D) false true 3
Apa yang terjadi Memahami equals () dan hashCode ()
Dalam perbandingan pertama, hasil equals()
true
, karena keadaan objek adalah sama, dan metode hashCode()
mengembalikan nilai yang sama untuk kedua objek.
Dalam perbandingan kedua, metode hashCode()
diganti untuk variabel hashCode()
. Untuk kedua objek Simpson
, namanya "Homer" , tetapi untuk overriddenHomer
metode hashCode()
mengembalikan nilai yang berbeda. Dalam kasus ini, hasil dari metode equals()
akan false
, karena berisi perbandingan dengan kode hash.
Anda harus menyadari bahwa akan ada tiga objek Simpson
dalam koleksi. Mari kita lakukan.
Objek pertama di set akan dimasukkan seperti biasa:
new Simpson("Homer");
Objek berikut ini juga akan dimasukkan dengan cara biasa, karena mengandung nilai yang berbeda dari objek sebelumnya:
new Simpson("Marge");
Akhirnya, objek Simpson
berikutnya memiliki nilai nama yang sama dengan objek pertama. Dalam hal ini, objek tidak akan dimasukkan:
set.add(new Simpson("Homer"));
Seperti yang kita ketahui, objek overridenHomer
menggunakan nilai hash yang berbeda, tidak seperti instance Simpson("Homer")
biasa Simpson("Homer")
. Karena alasan ini, item ini akan dimasukkan ke dalam koleksi:
set.add(overriddenHomer);
Jawabannya
Jawaban yang benar adalah B. Kesimpulannya adalah:
true false 3
Kesalahan umum dengan equals () dan hashCode ()
- Kurangnya menimpa
hashCode()
bersama dengan menimpa equals()
atau sebaliknya. - Kurangnya menimpa
equals()
dan hashCode()
saat menggunakan koleksi hash seperti HashSet
. - Mengembalikan nilai konstan dalam metode
hashCode()
alih-alih mengembalikan kode unik untuk setiap objek. - Penggunaan Setara
==
dan equals()
. Operator ==
membandingkan referensi objek, sedangkan metode equals()
membandingkan nilai objek.
Apa yang perlu Anda ingat tentang equals () dan hashCode ()
- Disarankan agar Anda selalu mengganti metode
equals()
dan hashCode()
di POJO Anda ( Rusia , Inggris ) - Gunakan algoritma yang efisien untuk membuat kode hash yang unik.
- Saat mengganti metode
equals()
, selalu timpa metode hashCode()
. - Metode
equals()
harus membandingkan keadaan lengkap objek (nilai dari bidang). - Metode
hashCode()
dapat menjadi pengidentifikasi POJO (ID). - Jika hasil membandingkan kode hash dari dua objek
false
, maka metode equals()
juga harus false
. - Jika
equals()
dan hashCode()
tidak didefinisikan ulang saat menggunakan koleksi hash, maka koleksi akan memiliki elemen duplikat.
Pelajari lebih lanjut tentang Java
Secara tradisional, saya menunggu komentar Anda dan mengundang Anda ke pelajaran terbuka , yang akan diadakan oleh guru kami Sergei Petrelevich pada 18 Maret