1. Java'da nesneleri karşılaştırma

Java'da nesneler hem referansa hem de değere göre karşılaştırılabilir.

referansları karşılaştırma

İki değişken bellekte aynı nesneyi gösteriyorsa, bu değişkenlerde depolanan referanslar eşittir. Eşitlik operatörünü ( ) kullanarak bu değişkenleri karşılaştırırsanız ==, doğru olur ve bu sonuç anlamlı olur. Burada her şey basit.

kod Konsol çıkışı
Integer a = 5;
Integer b = a;
System.out.println(a == b);


true

değere göre karşılaştırma

Ancak iki değişkenin aynı olan iki farklı nesneyi ifade ettiği durumlarla sıklıkla karşılaşabilirsiniz. Örneğin, aynı metni içeren iki farklı dize nesnesi.

Farklı nesnelerin aynı olup olmadığını belirlemek için equals()yöntemi kullanın. Örneğin:

kod Konsol çıkışı
String a = new String("Hello");
String b = new String("Hello");
System.out.println(a == b);
System.out.println(a.equals(b));


false
true

Yöntem equals, sınıfla sınırlı değildir String. Her sınıfta var.

Kendi başınıza yazdığınız sınıflar bile ve işte nedeni.



2. Objectsınıf

Java'daki tüm sınıflar, Objectsınıfı devralır. Java'nın yaratıcıları bu yaklaşımı ortaya attı.

Ve bir sınıf, sınıfı miras alırsa Object, sınıfın tüm yöntemlerini kazanır Object. Ve bu, mirasın önemli bir sonucudur.

ObjectBaşka bir deyişle, her sınıf , kodunda onlardan bahsetmese bile, sınıfın yöntemlerine sahiptir .

Bu kalıtsal yöntemler, nesne karşılaştırmasıyla ilgili yöntemleri içerir. Bunlar equals()ve hashCode()yöntemlerdir.

kod Gerçekte, sahip olacağımız şey şu:
class Person
{
   String name;
   int age;
}
class Person extends Object
{
   String name;
   int age;

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

   public int hashCode()
   {
      return address_of_object_in_memory; // This is the default implementation, but there may be a different implementation
   }
}

Yukarıdaki örnekte, Personad ve yaş parametreleriyle basit bir sınıf oluşturduk, ancak tek bir yöntem oluşturmadık. Ancak tüm sınıflar sınıfı devraldığından Object, Personsınıfın otomatik olarak iki yöntemi vardır:

Yöntem Tanım
boolean equals(Object obj)
Geçerli nesneyi ve geçirilen nesneyi karşılaştırır
int hashCode()
Geçerli nesnenin karma kodunu döndürür

equalsKesinlikle her nesnenin bir yöntemi olduğu ve farklı türdeki nesnelerin birbirleriyle karşılaştırılabileceği ortaya çıktı . Böyle bir kod mükemmel bir şekilde derlenecek ve çalışacaktır.

kod Konsol çıkışı
Integer a = 5;
String s = "Hello";
System.out.println(a.equals(s));
System.out.println(s.equals(a));


false
false
Object a = new Integer(5);
Object b = new Integer(5);
System.out.println(a.equals(b)) ;


true

3. equals()yöntem

equals()Sınıftan devralınan yöntem , Objectgeçerli nesneyi geçirilen nesnelerle karşılaştırmak için en basit algoritmayı uygular: yalnızca nesnelere yapılan referansları karşılaştırır.

PersonYöntemi çağırmak yerine sadece değişkenleri karşılaştırırsanız aynı sonucu alırsınız equals(). Örnek:

kod Konsol çıkışı
Person a = new Person();
a.name = "Steve";

Person b = new Person();
b.name = "Steve";

System.out.println(a == b);
System.out.println(a.equals(b));






false
false

Yöntem equalsçağrıldığında , değişkende saklanan referansı değişkende saklanan referansla akarşılaştırır .ab

Ancak, karşılaştırma sınıf için farklı çalışır String. Neden?

Çünkü sınıfı oluşturan insanlar, Stringyöntemin kendi uygulamalarını yazdılar equals().

equals()Yöntemin uygulanması

Şimdi sınıftaki eşittir yönteminin kendi uygulamamızı yazalım Person. 4 ana vakayı ele alacağız.

Önemli:
Yöntemi geçersiz kılan sınıf ne olursa olsun , her zaman bir nesneyi argüman olarak equalsalır.Object

Senaryo 1 : Yöntemin çağrıldığı aynı nesne equalsde yönteme iletilir equals. Geçerli nesnenin ve iletilen nesnenin başvuruları eşitse, yöntem döndürmelidir true. Bir nesne kendisine eşittir.

Kodda şöyle görünecek:

kod Tanım
public boolean equals(Object obj)
{
   if (this == obj)
    return true;

   // The rest of the code of the equals method
}


Referansları karşılaştırın

Senaryo 2 : nullyönteme geçirilir equals- karşılaştıracak hiçbir şeyimiz yok. Yöntemin çağrıldığı nesne kesinlikle null değildir, bu nedenle bu durumda equalsgeri dönmemiz gerekir .false

Kodda şöyle görünecek:

kod Tanım
public boolean equals(Object obj)
{
   if (this == obj)
      return true;

   if (obj == null)
      return false;

   // The rest of the code of the equals method
}


Referansları karşılaştır


Geçilen nesne mi null?

Senaryo 3 : a olmayan bir nesneye yapılan başvuru, Personyönteme iletilir equals. PersonNesne, nesne olmayana eşit midir Person? Bu, sınıfın geliştiricisinin Personnasıl isterse öyle karar vermesi gereken bir sorudur.

Ancak genellikle nesnelerin eşit kabul edilmesi için aynı sınıftan olması gerekir. PersonBu nedenle, equals yöntemimize sınıfın bir nesnesinden başka bir şey iletilirse, o zaman her zaman geri döneriz false. Bir nesnenin türünü nasıl kontrol edebilirsiniz? Bu doğru — operatörü kullanarak instanceof.

İşte yeni kodumuz şöyle görünüyor:

kod Tanım
public boolean equals(Object obj)
{
   if (this == obj)
      return true;

   if (obj == null)
      return false;

   if (!(obj instanceof Person))
      return false;

   // The rest of the code of the equals method
}


Referansları karşılaştır


Geçilen nesne mi null?


Geçirilen nesne birPerson

Person4. İki nesneyi karşılaştırma

Sonumuz ne oldu? Metodun sonuna ulaştıysak, Personolmayan bir nesne referansımız var demektir null. Bu yüzden onu a'ya dönüştürüyoruz Personve her iki nesnenin ilgili dahili verilerini karşılaştırıyoruz. Ve bu bizim dördüncü senaryomuz .

kod Tanım
public boolean equals(Object obj)
{
   if (this == obj)
      return true;

   if (obj == null)
      return false;

   if (!(obj instanceof Person))
      return false;

   Person person = (Person) obj;

   // The rest of the code of the equals method
}


Referansları karşılaştır


Geçilen nesne mi null? Geçirilen nesne bir Typecasting


değilsePerson


Ve iki nesneyi nasıl karşılaştırırsınız Person? nameİsimleri ( ) ve yaşları ( ) aynı ise eşittirler age. Nihai kod şöyle görünecektir:

kod Tanım
public boolean equals(Object obj)
{
   if (this == obj)
      return true;

   if (obj == null)
      return false;

   if (!(obj instanceof Person))
      return false;

   Person person = (Person) obj;

   return this.name == person.name && this.age == person.age;
}


Referansları karşılaştır


Geçilen nesne mi null? Geçirilen nesne bir Typecasting


değilsePerson


Ama hepsi bu kadar değil.

İlk olarak, ad alanı bir String, bu nedenle yöntemi çağırarak ad alanını karşılaştırmanız gerekir equals.

this.name.equals(person.name)

İkinci olarak, namealan şu şekilde olabilir : bu durumda onu nullarayamazsınız . equalsAşağıdakiler için ek bir kontrole ihtiyacınız var null:

this.name != null && this.name.equals(person.name)

Bununla birlikte, ad alanı nullher iki nesnedeyse Person, adlar yine de eşittir.

Dördüncü senaryonun kodu şöyle görünebilir:

Person person = (Person) obj;

if (this.age != person.age)
   return false;

if (this.name == null)
   return person.name == null;

return this.name.equals(person.name);


Yaşlar eşit değilse,
hemen return false

If this.nameeşittir ise null, yöntemi kullanarak karşılaştırma yapmanın bir anlamı yoktur equals. Burada ikinci namealan eşittir nullveya değildir.

Yöntemi kullanarak iki ad alanını karşılaştırın equals.


5. hashCode()yöntem

Her iki nesnenin tüm alanlarının ayrıntılı bir şekilde karşılaştırılmasını amaçlayan yönteme ek olarak equals, kesin olmayan ancak çok hızlı bir karşılaştırma için kullanılabilecek başka bir yöntem daha vardır: hashCode().

Binlerce kelimeden oluşan bir listeyi alfabetik olarak sıraladığınızı ve kelime çiftlerini tekrar tekrar karşılaştırmanız gerektiğini hayal edin. Ve kelimeler uzun, birçok harften oluşuyor. Genel olarak konuşursak, böyle bir karşılaştırma çok uzun zaman alır.

Ama hızlandırılabilir. Diyelim ki farklı harflerle başlayan kelimelerimiz var - farklı oldukları hemen anlaşılıyor. Ancak aynı harflerle başlarlarsa, sonucun ne olacağını henüz söyleyemeyiz: kelimeler eşit veya farklı olabilir.

Yöntem hashCode(), benzer bir ilkeye göre çalışır. Bir nesne üzerinde çağırırsanız, bir kelimedeki ilk harfe benzer bir sayı döndürür. Bu sayı aşağıdaki özelliklere sahiptir:

  • Özdeş nesneler her zaman aynı karma koda sahiptir
  • Farklı nesneler aynı karma koda sahip olabilir veya karma kodları farklı olabilir
  • Nesnelerin farklı karma kodları varsa, o zaman nesneler kesinlikle farklıdır

Bunu daha da açık hale getirmek için, bu özellikleri sözcükler açısından yeniden çerçevelendirelim:

  • Özdeş sözcüklerin baş harfleri her zaman aynıdır.
  • Farklı kelimelerin ilk harfleri aynı olabilir veya ilk harfleri farklı olabilir.
  • Kelimelerin ilk harfleri farklıysa, kelimeler kesinlikle farklıdır

Son özellik, nesnelerin karşılaştırılmasını hızlandırmak için kullanılır:

İlk olarak, iki nesnenin karma kodları hesaplanır. Bu karma kodlar farklıysa, o zaman nesneler kesinlikle farklıdır ve bunları daha fazla karşılaştırmaya gerek yoktur.

Ancak karma kodlar aynıysa, yine de eşittir yöntemini kullanarak nesneleri karşılaştırmamız gerekir.



6. Kodlu Sözleşmeler

Yukarıda açıklanan davranış, Java'daki tüm sınıflar tarafından uygulanmalıdır. Derleme sırasında, nesnelerin doğru bir şekilde karşılaştırılıp karşılaştırılmadığını kontrol etmenin bir yolu yoktur.

Java programcıları, equals() yönteminin kendi uygulamalarını yazarlarsa ve böylece standart uygulamayı (sınıfta Object) geçersiz kılarlarsa, yöntemin kendi uygulamalarını da hashCode()yukarıda belirtilen kuralları sağlayacak şekilde yazmaları gerektiği konusunda evrensel bir anlaşmaya sahiptir. memnun.

Bu düzenlemeye sözleşme denir .

Sınıfınızda yalnızca equals()veya yalnızca yöntemi uygularsanız , sözleşmeyi büyük ölçüde ihlal etmiş olursunuz (sözleşmeyi bozmuş olursunuz). hashCode()Bunu yapma.

Diğer programcılar kodunuzu kullanırsa düzgün çalışmayabilir. Dahası, yukarıdaki sözleşmelere uymaya dayalı kod kullanacaksınız.

Önemli!

Bir öğe ararken, tüm Java koleksiyonları önce nesnelerin hash kodlarını karşılaştırır ve ancak bundan sonra yöntemi kullanarak bir karşılaştırma gerçekleştirir equals.

Bu, kendi sınıfınıza bir yöntem verirseniz, equalsancak kendi yönteminizi yazmazsanız hashCode()veya yanlış uygularsanız, koleksiyonlar nesnelerinizle doğru çalışmayabilir.

Örneğin, bir listeye bir nesne ekleyebilir ve ardından yöntemi kullanarak onu arayabilirsiniz contains(), ancak koleksiyon nesnenizi bulamayabilir.