Obyektlarni Taqqoslash

All lectures for UZ purposes
Daraja, Dars
Mavjud

1. Java-da obyektlarni taqqoslash

Java-da obyektlarni link orqali yoki qiymat orqali taqqoslash mumkin.

Link orqali taqqoslash

Agar ikkita o'zgaruvchi xotirada bir xil obyektni ko'rsatsa, ushbu o'zgaruvchilarda saqlangan linklar teng bo'ladi. Bunday o'zgaruvchilarni == tenglik operatori yordamida taqqoslasangiz, true bo'ladi, bu mantiqan to'g'ri. Bu yerda hammasi oddiy.

Kod Ekrandagi Chiqish
Integer a = 5;
Integer b = a;
System.out.println(a == b);


true

Qiymat orqali taqqoslash

Biroq, ko'pincha ikkita o'zgaruvchi har xil, lekin bir xil obyektlarga ishora qilganida vaziyat yuzaga kelishi mumkin. Masalan, bir xil matnni o'zida saqlaydigan, lekin turli xil obyektlarda joylashgan ikkita satr.

Har xil obyektlarning bir xil ekanligini aniqlash uchun equals() metodidan foydalanish kerak. Misol:

Kod Ekrandagi Chiqish
String a = new String("Salom");
String b = new String("Salom");
System.out.println(a == b);
System.out.println(a.equals(b));


false
true

equals metodi faqat String klassida emas — bu hamma klasslarda mavjud.

Hatto siz faqatgina yozmoqchi bo'lgan klasslarda ham. Va nima uchun.



2. Object klassi

Java-dagi barcha klasslar Object klassidan meros qilib olingan deb hisoblanadi. Bu Java yaratuvchilari tomonidan o'ylab topilgan.

Agar biror klass Object klassidan meros qilib olingan bo'lsa, ushbu klassning merosxo'rida Object klassining barcha metodlari mavjud bo'ladi. Bu merosxo'rlikning asosiy ta'siri.

Boshqa so'z bilan aytganda, har bir klassda, Uni yozganingizdan qat'i nazar, Object klassiga tegishli bo'lgan barcha metodlar mavjud.

Va bunday metodlar orasida obyektlarni taqqoslash bilan bog'liq metodlar mavjud. Bu equals() va hashCode() metodlari.

Kod Aslida qanday bo'ladi:
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 адрес_объекта_в_памяти; //это дефолтная реализация, но может быть и другая }
}

Yuqoridagi misolda biz name va age parametrlariga ega Person degan oddiy klass yaratdik, hech qanday metodsiz. Biroq, barcha klasslar Object klassidan meros qilib olingan deb hisoblanishi sababli, Person klassida yashirincha ikki metod paydo bo'ldi:

Metod Tavsif
boolean equals(Object obj)
Joriy obyekt va uzatilgan obyektni taqqoslaydi
int hashCode()
Joriy obyektning hash-kodini qaytaradi

Natijada equals metodi barcha obyektlarda mavjud va turli tipdagi obyektlarni bir-biriga taqqoslash mumkin, va bu hammasi juda yaxshi kompilyatsiyalanadi va ishlaydi.

Kod Ekrandagi Chiqish
Integer a = 5;
String s = "Salom";
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() metodi

Object klassidan meros qilib olingan equals() metodi joriy va uzatilgan obyektlarni eng oddiy algoritm bilan taqqoslaydi — u faqat ularning linklarini taqqoslaydi.

Aynan shunday ta'sir siz Person klassi o'zgaruvchilarini oddiy qilib taqqoslaganingizda bo'ladi, equals() metodini chaqirish o'rniga. Misol:

Kod Ekrandagi Chiqish
Person a = new Person();
a.name = "Anya";

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

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






false
false

equals metodi o'z ichidagi a va b linklarini oddiygina taqqoslaydi.

Biroq String klassi uchun taqqoslash boshqa yo'l bilan ishlaydi. Nima uchun?

Chunki String klassini ishlab chiquvchilar equals() metodining o'zlarining o'ziga xos implementatsiyasini yozishgan.

equals() metodining implementatsiyasi

Keling, biz ham Person klassida equals metodining o'ziga xos implementatsiyasini yozamiz. 4 asosiy holatni ko'rib chiqamiz.

Muhim:
Qaysi klass uchun equals metodini qayta yozganingizdan qat'i nazar, u har doim Object tipidagi parametrni qabul qiladi.

Holat 1: equals metodiga aynan o'sha obyekt uzatilgan bo'lsa, unda equals metodini chaqirdik. Agar joriy va uzatilgan obyektlar linklari teng bo'lsa, true qaytarish kerak. Obyekt o'zi bilan o'zi mos keladi.

Kodda bu quyidagicha ko'rinadi:

Kod Tavsif
public boolean equals(Object obj)
{    if (this == obj)
    return true;

   equals metodining qolgan kodi
}


Linklarni taqqoslash

Holat 2: equals metodiga null ga ishora qiluvchi link uzatilgan — taqqoslashga hech narsa yo'q. equals metodini chaqirgan obyekt aniq null emas, shuning uchun bu holatda false qaytarish kerak.

Kodda bu quyidagicha ko'rinadi:

Kod Tavsif
public boolean equals(Object obj)
{
   if (this == obj)
      return true;

   if (obj == null)
      return false;

   equals metodining qolgan kodi
}


Linklarni taqqoslash


O'tkazilgan obyekt — null?

Holat 3: equals metodiga umuman Person klassidan bo'lmagan obyekt uzatilgan. Person klassi obyekti bo'lmagan obyekt bilan tengmi? Bu yerda Person klassi ishlab chiquvchisi qanday xohlasa, shunday qiladi.

Lekin, odatda, obyektlar bir xil tipdagi obyektlar sifatida teng hisoblanadi. Shuning uchun agar equals metodimizga Person klassidan bo'lmagan obyekt uzatilsa, biz har doim false qaytaramiz. Obyektning qanday turdaligini tekshirish uchun qanday operatorni ishlatish kerak? To'g'ri: instanceof operatori yordamida.

Bizning yangi kodimiz quyidagicha ko'rinadi:

Kod Tavsif
public boolean equals(Object obj)
{
   if (this == obj)
      return true;

   if (obj == null)
      return false;

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

   equals metodining qolgan kodi
}


Linklarni taqqoslash


O'tkazilgan obyekt — null?


Agar o'tkazilgan obyekt Person tipida bo'lmasa

4. Ikki Person obyektini taqqoslash

Nimani oldik? Agar metoding oxirigacha yetib kelsak, demak bizda Person tipida obyekt bor va link null emas. Undan keyin uni Person tipiga o'tkazamiz va ikkala obyektning ichki qismlarini taqqoslaymiz. Bu bizning to'rtinchi holatimiz.

Kod Tavsif
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;

   equals metodining qolgan kodi
}


Linklarni taqqoslash


O'tkazilgan obyekt — null?


Agar o'tkazilgan obyekt Person tipida bo'lmasa


Tipni o'tkazish operatsiyasi

Ikki Person obyektini qanday taqqoslash kerak? Ular faqatgina ismlari (name) va yoshlari (age) teng bo'lsa teng hisoblanadi. Yakuniy kod quyidagicha ko'rinadi:

Kod Tavsif
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;
}


Linklarni taqqoslash


O'tkazilgan obyekt — null?


Agar o'tkazilgan obyekt Person tipida bo'lmasa


Tipni o'tkazish operatsiyasi

Lekin bu ham hammasi emas.

Birinchidan, name maydoni String tipida bo'lgani uchun, name maydonini equals metodini chaqirish orqali taqqoslash kerak.

this.name.equals(person.name)

Ikkinchidan, name maydoni null bo'lishi mumkin: shunda bu maydon uchun equals metodini chaqirish mumkin emas. Qo'shimcha null tekshiruv kerak:

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

Biroq agar name ikkala Person obyektida null bo'lsa, isimlar tengdir.

To'rtinchi holatning kodini misol uchun quyidagicha yozish mumkin:

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);


Agar yoshlari teng bo'lmasa,
return false darhol

Agar this.name null ga teng bo'lsa, equals orqali taqqoslashning ma'nosi yo'q. Bu yerda ikkinchi name maydoni null ga teng yoki emas.

equals orqali ikki name fieldsini taqqoslash.


5. hashCode() metodi

equals metodidan tashqari, u barcha maydonlarning detalli taqqoslashini bajaradi, yana bir metod mavjud bo'lib, u aniq bo'lmagan, lekin juda tez taqqoslash uchun ishlatilishi mumkin — hashCode().

Faraz qiling, siz alfavit tartibida minglab so'zlardan iborat ro'yxatni saralamoqdasiz va siz doimo so'zlarni juft-juft taqqoslashingiz kerak. So'zlar uzun, harflar ko'p. Xullas, bu taqqoslash juda uzoq davom etadi.

Biroq uni tezlashtirish mumkin. Masalan, so'zlar turli harflardan boshlanadi: darhol ular turli ekanligi ma'lum bo'ladi. Agar ular bir xil harflardan boshlansa, keyin esa hech qanday kafolat yo'q: keyinchalik so'zlar ham teng, ham turli bo'lishi mumkin.

Metod hashCode() shu kabi tamoyilda ishlaydi. Agar obyektdan chaqirilsa, u biror raqam qaytaradi — bu so'zning birinchi harfiga o'xshaydi. Ushbu raqam quyidagi xususiyatlarga ega:

  • Teng obyektlar har doim bir xil hash-kodga ega
  • Turli obyektlar bir xil hash-kodga ega bo'lishi mumkin, yoki har xil
  • Agar objeklar hash-kodlari turlicha bo'lsa, obyektlar aniq turli

Ko'proq tushuncha uchun ushbu xususiyatlarni so'zlarga nisbatan qayta yozamiz:

  • Teng so'zlar har doim bir xil birinchi harflarga ega
  • Turli so'zlar bir xil birinchi harflarga ega bo'lishi mumkin yoki har xil
  • Agar so'zlarning birinchi harflari turlicha bo'lsa, so'zlar aniq turli

Oxirgi xususiyat obyektlarni tez taqqoslashda ishlatiladi:

Dastlab ikki obyektning hash-kodlari hisoblanadi. Agar bu hash-kodlar har xil bo'lsa, obyektlar aniq turli va ularni keyinchalik taqqoslash shart emas.

Agar hash-kodlar bir xil bo'lsa, obyektlarni equals yordamida taqqoslash kerak bo'ladi.



6. Kodda kontraktlar

Yuqorida tasvirlangan harakatlar Java-dagi barcha klasslar tomonidan amalga oshirilishi kerak. Obyektlarni to'g'ri taqqoslashni darajaviy insofsizlik yoki xatolarni tekshirishning hech qanday yo'li yo'q.

Barcha Java-dasturchilari kelishib olishgan, agar ular o'z equals() metodining implementatsiyasini yozishsa, standarta o'rniga (Object klassidan), ular shuningdek hashCode() metodini ham o'z implementatsiyasini yozishga majbur, shunda yuqorida aytib o'tilgan qoidalar saqlanadi.

Bunday kelishuv kontrakt deb ataladi.

Agar siz o'z klassingizga faqat bitta equals() yoki faqat hashCode() metodining implementatsiyasini qo'shsangiz, siz qo'pol ravishda kontraktni (kelishuvni) buzgan bo'lasiz. Bunday qilish mumkin emas.

Boshqa dasturchilar sizning kodingizni ishlatganida, u noto'g'ri ishlashi mumkin. Bundan tashqari, siz ham yuqorida aytilgan kontraktlarga asoslangan kodlardan foydalanasiz.

Muhim!

Java-dagi barcha kolleksiyalar ichidagi elementni qidirishda birinchi navbatda obyektlarning hash-kodlarini taqqoslashadi, keyin esa taqqoslash uchun equals metodini chaqiradi.

Shuning uchun agar siz o'z klasangizni yozsangiz va yangi equals metodini qo'shsangiz, lekin hashCode() metodini yozmasangiz yoki uni xatolar bilan amalga oshirsangiz, kolleksiyalar sizning obyektlaringiz bilan noto'g'ri ishlashi mumkin.

Masalan, siz ob'ektni ro'yxatga qo'shgan bo'lsangiz, so'ngra contains() metod yordamida uni qidirsangiz, kolleksiya sizning obyektingizni topmasligi mumkin.

Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION