"Sekarang saya akan memberi tahu Anda tentang beberapa metode yang sama membantunya:  equals(Object o) & hashCode() ."

"Anda mungkin sudah ingat bahwa, di Jawa, saat membandingkan variabel referensi, objek itu sendiri tidak dibandingkan, melainkan referensi ke objek."

Kode Penjelasan
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i==j);
i tidak sama dengan j
Variabel menunjuk ke objek yang berbeda.
Meskipun objek berisi data yang sama.
Integer i = new Integer(1);
Integer j = i;
System.out.println(i==j);
saya sama dengan j. Variabel berisi referensi ke objek yang sama.

"Ya, aku ingat itu."

Yang  sederajat .

"Metode yang sama adalah solusi standar di sini. Tujuan dari metode yang sama adalah untuk menentukan apakah objek identik secara internal dengan membandingkan apa yang disimpan di dalamnya."

"Dan bagaimana caranya?"

"Semuanya sangat mirip dengan metode toString()."

Kelas Object memiliki implementasi sendiri dari metode equals, yang hanya membandingkan referensi:

public boolean equals(Object obj)
{
return (this == obj);
}

"Hebat ... kembali ke itu lagi, kan?"

"Pertahankan dagumu! Ini sebenarnya sangat rumit."

"Metode ini dibuat untuk memungkinkan pengembang menimpanya di kelas mereka sendiri. Lagi pula, hanya pengembang kelas yang tahu data apa yang relevan dan apa yang tidak saat membandingkan."

"Bisakah Anda memberikan contoh?"

"Tentu. Misalkan kita memiliki kelas yang merepresentasikan pecahan matematika. Akan terlihat seperti ini:"

Contoh:
class Fraction
{
private int numerator;
private int denominator;
Fraction(int numerator, int denominator)
{
this.numerator  = numerator;
this.denominator = denominator;
}public boolean equals(Object obj)
{
if (obj==null)
return false;

if (obj.getClass() != this.getClass() )
return false;

Fraction other = (Fraction) obj;
return this.numerator* other.denominator == this.denominator * other.numerator;
}
}
Contoh pemanggilan metode:
Fraction one = new Fraction(2,3);
Fraction two = new Fraction(4,6);
System.out.println(one.equals(two));
Pemanggilan metode akan mengembalikan true.
Pecahan 2/3 sama dengan pecahan 4/6

"Sekarang, mari kita membedah contoh ini."

"Kami mengesampingkan metode yang sama , sehingga objek Fraksi akan memiliki implementasinya sendiri.

"Ada beberapa pemeriksaan dalam metode ini:"

" 1)  Jika objek yang dilewatkan untuk perbandingan adalah null , maka objek tersebut tidak sama. Jika Anda dapat memanggil metode equals pada suatu objek, maka objek tersebut pasti bukan null ."

" 2)  Perbandingan kelas. Jika objek adalah instance dari kelas yang berbeda, maka kami tidak akan mencoba membandingkannya. Sebagai gantinya, kami akan segera menggunakan return false untuk menunjukkan bahwa ini adalah objek yang berbeda."

" 3)  Semua orang ingat dari kelas dua bahwa 2/3 sama dengan 4/6. Tapi bagaimana cara memeriksanya?"

2/3 == 4/6
Kami mengalikan kedua sisi dengan kedua pembagi (6 dan 3), dan kami mendapatkan:
6 * 2 == 4 * 3
12 == 12
Peraturan umum:
Jika
a / b == c / d
Maka
a * d == c * b

"Oleh karena itu, di bagian ketiga dari metode sama dengan , kami melemparkan objek yang diteruskan ke Pecahan dan membandingkan pecahannya."

"Mengerti. Jika kita hanya membandingkan pembilang dengan pembilang dan penyebut dengan penyebut, maka 2/3 tidak sama dengan 4/6."

"Sekarang saya mengerti apa yang Anda maksud ketika Anda mengatakan bahwa hanya pengembang kelas yang tahu bagaimana membandingkannya dengan benar."

"Ya, tapi itu baru separuh cerita.  Ada metode lain: kode hash(). "

"Segala sesuatu tentang metode sama masuk akal sekarang, tetapi mengapa kita membutuhkan  kode hash ()? "

" Metode hashCode diperlukan untuk perbandingan cepat."

" Metode equals memiliki kelemahan besar: bekerja terlalu lambat. Misalkan Anda memiliki satu set jutaan elemen dan perlu memeriksa apakah itu berisi objek tertentu. Bagaimana Anda melakukannya?"

"Saya bisa menggilir semua elemen menggunakan loop dan membandingkan objek dengan setiap objek di set. Sampai saya menemukan kecocokan."

"Dan jika tidak ada? Kami akan melakukan sejuta perbandingan hanya untuk mengetahui bahwa benda itu tidak ada? Bukankah itu terlihat banyak?"

"Ya, bahkan aku menyadari itu terlalu banyak perbandingan. Apakah ada cara lain?"

"Ya, Anda dapat menggunakan kode hash () untuk ini.

Metode kode hash () mengembalikan nomor tertentu untuk setiap objek. Pengembang kelas memutuskan nomor apa yang dikembalikan, seperti yang dia lakukan untuk metode yang sama.

"Mari kita lihat sebuah contoh:"

"Bayangkan Anda memiliki sejuta angka 10 digit. Kemudian, Anda dapat membuat kode hash setiap angka menjadi sisanya setelah membagi angka tersebut dengan 100."

Berikut contohnya:

Nomor Kode hash kami
1234567890 90
9876554321 21
9876554221 21
9886554121 21

"Ya, itu masuk akal. Dan apa yang kita lakukan dengan kode hash ini?"

"Alih-alih membandingkan angka, kami membandingkan kode hash mereka . Lebih cepat seperti itu."

"Dan kami memanggil sama hanya jika kode hash mereka sama."

"Ya, itu lebih cepat. Tapi kita masih harus membuat sejuta perbandingan. Kita hanya membandingkan angka yang lebih kecil, dan kita masih harus memanggil sama untuk setiap angka dengan kode hash yang cocok."

"Tidak, Anda bisa lolos dengan jumlah perbandingan yang jauh lebih kecil."

"Bayangkan Set kami menyimpan nomor yang dikelompokkan atau diurutkan berdasarkan kode hash (mengurutkannya dengan cara ini pada dasarnya mengelompokkannya, karena nomor dengan kode hash yang sama akan bersebelahan). Kemudian Anda dapat membuang grup yang tidak relevan dengan sangat cepat dan mudah. ​​Sudah cukup untuk memeriksa sekali per grup untuk melihat apakah kode hashnya cocok dengan kode hash objek."

"Bayangkan Anda seorang mahasiswa yang sedang mencari teman yang dapat Anda kenali secara kasat mata dan yang kita kenal tinggal di Asrama 17. Kemudian Anda pergi ke setiap asrama di universitas dan bertanya, 'Apakah ini Asrama 17?' Jika tidak, maka Anda mengabaikan semua orang di asrama dan melanjutkan ke yang berikutnya. Jika jawabannya 'ya', Anda mulai berjalan melewati setiap kamar, mencari teman Anda."

"Dalam contoh ini, nomor asrama (17) adalah kode hash."

"Pengembang yang mengimplementasikan fungsi kode hash harus mengetahui hal berikut:"

A)  dua objek yang berbeda dapat memiliki kode hash yang sama  (orang yang berbeda dapat tinggal di asrama yang sama)

B)  objek yang sama  ( menurut metode equalsharus memiliki kode hash yang sama. .

C)  kode hash harus dipilih agar tidak banyak objek berbeda dengan kode hash yang sama.  Jika ada, maka keuntungan potensial kode hash hilang (Anda tiba di Asrama 17 dan menemukan bahwa separuh universitas tinggal di sana. Nyebelin!).

"Dan sekarang hal yang paling penting. Jika Anda mengganti metode yang sama , Anda benar-benar harus mengganti metode kode hash () dan mematuhi tiga aturan yang dijelaskan di atas.

"Alasannya begini: di Java, objek dalam koleksi selalu dibandingkan/diambil menggunakan kode hash() sebelum dibandingkan/diambil menggunakan yang sama.  Dan jika objek yang identik memiliki kode hash yang berbeda, maka objek akan dianggap berbeda dan metode yang sama bahkan tidak akan dipanggil.

"Dalam contoh Pecahan kita, jika kita membuat kode hash sama dengan pembilangnya, pecahan 2/3 dan 4/6 akan memiliki kode hash yang berbeda. Pecahannya sama dan metode equals mengatakan bahwa mereka sama, tetapi kode hash mereka menyatakan mereka berbeda. Dan jika kita membandingkan menggunakan kode hash sebelum kita membandingkan menggunakan sama, maka kita menyimpulkan bahwa objeknya berbeda dan kita bahkan tidak pernah membuatnya menjadi metode yang sama."

Berikut contohnya:

HashSet<Fraction>set = new HashSet<Fraction>();
set.add(new Fraction(2,3));System.out.println( set.contains(new Fraction(4,6)) );
Jika metode hashCode()  mengembalikan pembilang pecahan, hasilnya akan  false .
Dan objek «New Fraction(4,6) » tidak akan ditemukan di koleksi.

"Jadi, apa cara yang tepat untuk mengimplementasikan kode hash untuk pecahan?"

"Di sini Anda perlu mengingat bahwa pecahan setara harus memiliki kode hash yang sama."

" Versi 1 : kode hash sama dengan hasil pembagian bilangan bulat."

"Untuk 7/5 dan 6/5, ini akan menjadi 1."

"Untuk 4/5 dan 3/5, ini akan menjadi 0."

"Tapi opsi ini kurang cocok untuk membandingkan pecahan yang sengaja dibuat kurang dari 1. Kode hash (hasil pembagian bilangan bulat) akan selalu 0."

" Versi 2 : kode hash sama dengan hasil pembagian bilangan bulat penyebut dengan pembilang."

"Pilihan ini cocok untuk contoh di mana pecahannya kurang dari 1. Jika pecahannya kurang dari 1, maka kebalikannya lebih besar dari 1. Dan jika kita membalikkan semua pecahan, maka perbandingannya sama sekali tidak terpengaruh."

"Versi terakhir kami menggabungkan kedua solusi:"

public int hashCode()
{
return numerator/denominator + denominator/numerator;
}

Mari kita uji menggunakan 2/3 dan 4/6. Mereka harus memiliki kode hash yang identik:

Pecahan 2/3 Pecahan 4/6
pembilang/penyebut 2/3 == 0 4/6 == 0
penyebut / pembilang 3 / 2 == 1 6/4 == 1
pembilang / penyebut
+
penyebut / pembilang
0 + 1 == 1 0 + 1 == 1

"Itu saja untuk saat ini."

"Terima kasih, Ellie. Itu sangat menarik."