"Şimdi size aynı derecede yardımcı olan bazı yöntemlerden bahsedeceğim:  equals(Object o) & hashCode() ."

"Java'da referans değişkenlerini karşılaştırırken nesnelerin kendilerinin değil, nesnelere yapılan referansların karşılaştırıldığını muhtemelen zaten hatırlamışsınızdır."

kod Açıklama
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i==j);
i eşittir j değil
Değişkenler farklı nesneleri işaret ediyor.
Nesneler aynı verileri içermesine rağmen.
Integer i = new Integer(1);
Integer j = i;
System.out.println(i==j);
i eşittir j Değişkenler aynı nesneye bir referans içerir.

"Evet, bunu hatırlıyorum."

eşittir  . _

"Eşittir yöntemi burada standart çözümdür. Eşittir yönteminin amacı, nesnelerin içlerinde depolananları karşılaştırarak dahili olarak aynı olup olmadığını belirlemektir."

"Peki bunu nasıl yapıyor?"

"Hepsi toString() yöntemine çok benzer."

Object sınıfı, basitçe referansları karşılaştıran, eşittir yönteminin kendi uygulamasına sahiptir:

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

"Harika... yine buna dönelim, değil mi?"

"Çeneni yukarıda tut! Aslında çok zor."

"Bu yöntem, geliştiricilerin kendi sınıflarında onun üzerine yazmasına izin vermek için oluşturuldu. Ne de olsa, yalnızca bir sınıfın geliştiricisi karşılaştırma yaparken hangi verilerin alakalı olup neyin olmadığını bilir."

"Bir örnek verebilir misiniz?"

"Elbette. Matematiksel kesirleri temsil eden bir sınıfımız olduğunu varsayalım. Şuna benzer:"

Örnek:
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;
}
}
Örnek yöntem çağrısı:
Fraction one = new Fraction(2,3);
Fraction two = new Fraction(4,6);
System.out.println(one.equals(two));
Yöntem çağrısı true değerini döndürür.
2/3 kesri 4/6 kesrine eşittir

"Şimdi, bu örneği inceleyelim."

" Eşittir yöntemini geçersiz kıldık , böylece Kesir nesnelerinin kendi uygulamaları olacaktır.

"Yöntemde birkaç kontrol var:"

" 1)  Karşılaştırma için iletilen nesne null ise, o zaman nesneler eşit değildir. Bir nesne üzerinde equals yöntemini çağırabiliyorsanız , o zaman kesinlikle null değildir ."

" 2)  Bir sınıf karşılaştırması. Nesneler farklı sınıfların örnekleriyse, onları karşılaştırmaya çalışmayacağız. Bunun yerine, bunların farklı nesneler olduğunu belirtmek için hemen false döndüreceğiz."

" 3)  Herkes 2/3'ün 4/6'ya eşit olduğunu ikinci sınıftan hatırlıyor. Peki bunu nasıl kontrol edeceksiniz?"

2/3 == 4/6
Her iki tarafı da bölenlerle (6 ve 3) çarparız ve şunu elde ederiz:
6 * 2 == 4 * 3
12 == 12
Genel kural:

a / b == c / d ise
o zaman
a * d == c * b

"Buna göre, eşittir yönteminin üçüncü bölümünde , iletilen nesneyi bir Kesir'e atıyoruz ve kesirleri karşılaştırıyoruz."

"Anladım. Payı payla ve paydayı paydayla karşılaştırırsak, o zaman 2/3, 4/6'ya eşit değildir."

"Yalnızca bir sınıfın geliştiricisinin doğru karşılaştırmayı bildiğini söylerken ne demek istediğini şimdi anlıyorum."

"Evet, ama bu hikayenin sadece yarısı.  Başka bir yöntem daha var: hashCode(). "

"Eşittir yöntemiyle ilgili her şey şimdi mantıklı, ama neden  hashCode ()'a ihtiyacımız var? "

" Hızlı karşılaştırmalar için hashCode yöntemi gereklidir."

" Eşittir yönteminin büyük bir dezavantajı var: çok yavaş çalışıyor. Diyelim ki milyonlarca öğeden oluşan bir Kümeniz var ve bunun belirli bir nesne içerip içermediğini kontrol etmeniz gerekiyor. Bunu nasıl yaparsınız?"

"Bir döngü kullanarak tüm öğeler arasında geçiş yapabilir ve nesneyi setteki her nesneyle karşılaştırabilirim. Bir eşleşme bulana kadar."

"Ve eğer orada değilse? Sırf nesnenin orada olmadığını anlamak için milyonlarca karşılaştırma yaparız? Bu çok fazla görünmüyor mu?"

"Evet, ben bile bunun çok fazla karşılaştırma olduğunun farkındayım. Başka bir yolu var mı?"

"Evet, bunun için hashCode () kullanabilirsiniz .

hashCode () yöntemi , her nesne için belirli bir sayı döndürür. Bir sınıfın geliştiricisi, eşittir yöntemi için yaptığı gibi hangi sayının döndürüleceğine karar verir.

"Bir örneğe bakalım:"

"Bir milyon 10 basamaklı sayınız olduğunu hayal edin. Ardından, sayıyı 100'e böldükten sonra her sayının hashCode'unu kalan olarak yapabilirsiniz."

İşte bir örnek:

Sayı hashCode'umuz
1234567890 90
9876554321 21
9876554221 21
9886554121 21

"Evet, bu mantıklı. Peki bu hashCode ile ne yapacağız?"

"Sayıları karşılaştırmak yerine hashCode'larını karşılaştırıyoruz . Böylesi daha hızlı."

"Ve sadece hashCode'ları eşitse eşittir diyoruz ."

"Evet, bu daha hızlı. Ama yine de bir milyon karşılaştırma yapmamız gerekiyor. Yalnızca daha küçük sayıları karşılaştırıyoruz ve yine de eşleşen hashCode'lara sahip tüm sayılar için eşittir dememiz gerekiyor."

"Hayır, çok daha az sayıda karşılaştırma yaparak paçayı sıyırabilirsin."

"Setimizin hashCode'a göre gruplandırılmış veya sıralanmış sayıları sakladığını hayal edin (bu şekilde sıralamak aslında onları gruplandırmak demektir, çünkü aynı hashCode'a sahip sayılar yan yana olacaktır). O zaman ilgisiz grupları çok hızlı ve kolay bir şekilde atabilirsiniz. Bu yeterli hashCode'unun nesnenin hashCode'u ile eşleşip eşleşmediğini görmek için grup başına bir kez kontrol etmek için."

"Yurt 17'de yaşadığını bildiğimiz, gözünden tanıyacağı bir arkadaş arayan bir öğrenci olduğunuzu hayal edin. Sonra üniversitedeki her yurda gidip 'Burası 17. Yurt mu?' diye soruyorsunuz. Değilse, yurttaki herkesi görmezden gelir ve bir sonrakine geçersiniz.Cevap 'evet' ise, o zaman her bir odanın önünden geçerek arkadaşınızı aramaya başlarsınız."

"Bu örnekte yurt numarası (17) hashCode'dur."

"Bir hashCode işlevini uygulayan bir geliştirici aşağıdakileri bilmelidir:"

A)  iki farklı nesne aynı hashCode'a sahip olabilir  (aynı yurtta farklı kişiler yaşayabilir)

B)  aynı olan nesneler  ( equals yöntemine göreaynı hashCode'a sahip olmalıdır. .

C)  hash kodları, aynı hashCode'a sahip çok sayıda farklı nesne olmayacak şekilde seçilmelidir.  Varsa, hash kodlarının potansiyel avantajları kaybolur (Yurt 17'ye gidersiniz ve üniversitenin yarısının orada yaşadığını görürsünüz. Serseri!).

"Ve şimdi en önemli şey. Equals yöntemini geçersiz kılıyorsanız , mutlaka hashCode () yöntemini geçersiz kılmalı ve yukarıda açıklanan üç kurala uymalısınız.

"Bunun nedeni şudur: Java'da, bir koleksiyondaki nesneler, equals kullanılarak karşılaştırılmadan/alınmadan önce her zaman hashCode() kullanılarak karşılaştırılır/alınır.  Ve aynı nesnelerin farklı hashCode'ları varsa, o zaman nesneler farklı kabul edilir ve eşittir yöntemi çağrılmayacak bile

"Kesir örneğimizde hashCode'u paya eşitleseydik, 2/3 ve 4/6 kesirlerinin hashCode'ları farklı olurdu. Kesirler aynıdır ve equals yöntemi bunların aynı olduğunu söyler, ancak hashCode'ları der ki ve eğer equals kullanarak karşılaştırmadan önce hashCode kullanarak karşılaştırırsak, o zaman nesnelerin farklı olduğu sonucuna varırız ve asla equals yöntemine bile ulaşamayız."

İşte bir örnek:

HashSet<Fraction>set = new HashSet<Fraction>();
set.add(new Fraction(2,3));System.out.println( set.contains(new Fraction(4,6)) );
hashCode ()  yöntemi kesirlerin payını döndürürse sonuç  false olur .
Ve «new Fraction(4,6) » nesnesi koleksiyonda bulunmayacaktır.

"Öyleyse kesirler için hashCode'u uygulamanın doğru yolu nedir?"

"Burada, eşdeğer kesirlerin aynı hashCode'a sahip olması gerektiğini hatırlamanız gerekir."

" Versiyon 1 : hashCode, tamsayı bölme işleminin sonucuna eşittir."

"7/5 ve 6/5 için bu 1 olur."

"4/5 ve 3/5 için bu 0 olur."

"Ancak bu seçenek, kasıtlı olarak 1'den küçük olan kesirleri karşılaştırmak için pek uygun değil. hashCode (tamsayı bölmenin sonucu) her zaman 0 olacaktır."

" Sürüm 2 : hashCode, paydanın pay ile tamsayı bölümünün sonucuna eşittir."

"Bu seçenek, kesrin 1'den küçük olduğu durumlar için uygundur. Kesir 1'den küçükse, tersi 1'den büyüktür. Ve tüm kesirleri tersine çevirirsek, karşılaştırmalar hiçbir şekilde etkilenmez."

"Son versiyonumuz her iki çözümü de birleştiriyor:"

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

2/3 ve 4/6 kullanarak test edelim. Aynı hashCode'lara sahip olmalıdırlar:

kesir 2/3 kesir 4/6
pay / payda 2 / 3 == 0 4 / 6 == 0
payda / pay 3 / 2 == 1 6 / 4 == 1
pay / payda
+
payda / pay
0 + 1 == 1 0 + 1 == 1

"Şimdilik bu kadar."

"Teşekkürler Ellie. Bu gerçekten ilginçti."