1. Paghahambing ng mga bagay sa Java

Sa Java, ang mga bagay ay maaaring ihambing pareho sa pamamagitan ng sanggunian at sa pamamagitan ng halaga.

Paghahambing ng mga sanggunian

Kung ang dalawang variable ay tumuturo sa parehong bagay sa memorya, kung gayon ang mga sanggunian na nakaimbak sa mga variable na ito ay pantay. Kung ihahambing mo ang mga variable na ito gamit ang equality operator ( ==), makakakuha ka ng totoo, at ang resultang iyon ay may katuturan. Simple lang ang lahat dito.

Code Output ng console
Integer a = 5;
Integer b = a;
System.out.println(a == b);


true

Paghahambing ayon sa halaga

Ngunit madalas kang makakatagpo ng mga sitwasyon kung saan ang dalawang variable ay tumutukoy sa dalawang natatanging bagay na magkapareho. Halimbawa, dalawang magkaibang string na mga bagay na naglalaman ng parehong teksto.

Upang matukoy kung magkapareho ang iba't ibang bagay, gamitin ang equals()pamamaraan. Halimbawa:

Code Output ng console
String a = new String("Hello");
String b = new String("Hello");
System.out.println(a == b);
System.out.println(a.equals(b));


false
true

Ang equalspamamaraan ay hindi limitado sa Stringklase. Bawat klase meron nito.

Maging ang mga klase na ikaw mismo ang nagsusulat, at narito kung bakit.



2. Objectklase

Lahat ng klase sa Java ay nagmamana ng Objectklase. Ang mga tagalikha ng Java ay gumawa ng diskarteng ito.

At kung ang isang klase ay nagmamana ng Objectklase, pagkatapos ay nakukuha nito ang lahat ng mga pamamaraan ng Objectklase. At ito ay isang malaking kahihinatnan ng mana.

Sa madaling salita, ang bawat klase ay may mga pamamaraan ng Objectklase, kahit na ang kanilang code ay hindi binanggit ang mga ito.

Kasama sa mga minanang pamamaraang ito ang mga pamamaraang nauugnay sa paghahambing ng bagay. Ito ang mga equals()at hashCode()pamamaraan.

Code Sa katotohanan, narito ang makukuha natin:
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
   }
}

Sa halimbawa sa itaas, gumawa kami ng isang simpleng Personklase na may mga parameter ng pangalan at edad, ngunit hindi isang paraan. Ngunit dahil namamana ng lahat ng klase ang Objectklase, Personawtomatikong mayroong dalawang pamamaraan ang klase:

Pamamaraan Paglalarawan
boolean equals(Object obj)
Inihahambing ang kasalukuyang bagay at ang naipasa na bagay
int hashCode()
Ibinabalik ang hashcode ng kasalukuyang bagay

Ito ay lumalabas na ganap na ang bawat bagay ay may equalspamamaraan, at ang mga bagay ng iba't ibang uri ay maaaring ihambing sa bawat isa. Ang ganitong code ay mag-compile at gagana nang perpekto.

Code Output ng console
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()paraan

Ang equals()pamamaraan, na minana mula sa Objectklase, ay nagpapatupad ng pinakasimpleng algorithm para sa paghahambing ng kasalukuyang bagay sa mga naipasa na bagay: ito ay naghahambing lamang ng mga sanggunian sa mga bagay.

Makakakuha ka ng parehong resulta kung ihahambing mo lamang Personang mga variable sa halip na tawagan ang equals()pamamaraan. Halimbawa:

Code Output ng console
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

Kapag equalstinawag ang pamamaraan sa a, inihahambing lamang nito ang reference na nakaimbak sa avariable sa reference na nakaimbak sa bvariable.

Gayunpaman, ang paghahambing ay gumagana nang iba para sa Stringklase. Bakit?

Dahil ang mga taong lumikha ng Stringklase ay nagsulat ng kanilang sariling pagpapatupad ng equals()pamamaraan.

Pagpapatupad ng equals()pamamaraan

Ngayon ay isulat natin ang sarili nating pagpapatupad ng equals method sa Personklase. Isasaalang-alang namin ang 4 na pangunahing kaso.

Mahalaga:
Hindi alintana kung aling klase ang nag-o-override sa equalspamamaraan, palaging tumatagal ng isang Objectbagay bilang isang argumento

Sitwasyon 1 : ang parehong bagay kung saan equalstinatawag ang pamamaraan ay ipinapasa din sa equalspamamaraan. Kung ang mga sanggunian ng kasalukuyang bagay at ang naipasa na bagay ay pantay, ang pamamaraan ay dapat bumalik true. Ang isang bagay ay katumbas ng sarili nito.

Sa code ito ay magiging ganito:

Code Paglalarawan
public boolean equals(Object obj)
{
   if (this == obj)
    return true;

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


Ihambing ang mga sanggunian

Scenario 2 : nullay ipinasa sa equalspamamaraan — wala tayong maihahambing. Ang bagay kung saan equalstinawag ang pamamaraan ay tiyak na hindi null, kaya kailangan nating bumalik falsesa kasong ito.

Sa code ito ay magiging ganito:

Code Paglalarawan
public boolean equals(Object obj)
{
   if (this == obj)
      return true;

   if (obj == null)
      return false;

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


Ihambing ang mga sanggunian


Ay ang naipasa bagay null?

Sitwasyon 3 : isang sanggunian sa isang bagay na hindi isang Personay ipinasa sa equalspamamaraan. Ang Personbagay ba ay katumbas ng hindi Personbagay? Iyon ay isang tanong para sa developer ng Personklase na magpasya kung ano man ang gusto niya.

Ngunit kadalasan ang mga bagay ay dapat sa parehong klase upang maituring na pantay. Samakatuwid, kung ang isang bagay maliban sa isang bagay ng Personklase ay ipinasa sa aming katumbas na pamamaraan, pagkatapos ay palagi kaming babalik false. Paano mo masusuri ang uri ng isang bagay? Tama iyon — sa pamamagitan ng paggamit ng instanceofoperator.

Narito ang hitsura ng aming bagong code:

Code Paglalarawan
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
}


Ihambing ang mga sanggunian


Ay ang naipasa bagay null?


Kung ang ipinasang bagay ay hindi aPerson

4. Paghahambing ng dalawang Personbagay

Ano ang natapos namin? Kung naabot na natin ang dulo ng pamamaraan, mayroon tayong Personobject reference na hindi null. Kaya't iko-convert namin ito sa isang Personat inihambing ang nauugnay na panloob na data ng parehong mga bagay. At iyon ang aming ikaapat na senaryo .

Code Paglalarawan
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
}


Ihambing ang mga sanggunian


Ay ang naipasa bagay null?


Kung ang naipasa na bagay ay hindi isang Person


Typecasting

At paano mo ihahambing ang dalawang Personbagay? Pantay sila kung magkapareho sila ng pangalan ( name) at edad ( age). Ang huling code ay magiging ganito:

Code Paglalarawan
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;
}


Ihambing ang mga sanggunian


Ay ang naipasa bagay null?


Kung ang naipasa na bagay ay hindi isang Person


Typecasting

Ngunit hindi lang iyon.

Una, ang field ng pangalan ay isang String, kaya kailangan mong ihambing ang field ng pangalan sa pamamagitan ng pagtawag sa equalspamamaraan.

this.name.equals(person.name)

Pangalawa, ang namefield ay maaaring null: sa kasong iyon, hindi ka maaaring tumawag equalsdito. Kailangan mo ng karagdagang tseke para sa null:

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

Iyon ay sinabi, kung ang field ng pangalan ay nullnasa parehong Personmga bagay, kung gayon ang mga pangalan ay pantay pa rin.

Ang code para sa ikaapat na senaryo ay maaaring magmukhang ganito:

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


Kung ang mga edad ay hindi pantay,
kaagad return false

Kung this.nameay katumbas ng null, walang punto sa paghahambing gamit ang equalspamamaraan. Dito, ang pangalawang namefield ay katumbas ng null, o hindi.

Ihambing ang dalawang patlang ng pangalan gamit ang equalspamamaraan.


5. hashCode()paraan

Bilang karagdagan sa equalspamamaraan, na nilayon upang magsagawa ng isang detalyadong paghahambing ng lahat ng mga patlang ng parehong mga bagay, mayroong isa pang paraan na maaaring magamit para sa isang hindi tumpak ngunit napakabilis na paghahambing: hashCode().

Isipin na nag-uuri ka ayon sa alpabeto ng isang listahan ng libu-libong salita, at kailangan mong paulit-ulit na paghambingin ang mga pares ng mga salita. At ang mga salita ay mahaba, na binubuo ng maraming mga titik. Sa pangkalahatan, ang gayong paghahambing ay tatagal ng napakatagal.

Ngunit maaari itong mapabilis. Ipagpalagay na mayroon tayong mga salita na nagsisimula sa iba't ibang mga titik — malinaw agad na magkaiba ang mga ito. Ngunit kung nagsisimula sila sa parehong mga titik, hindi pa natin masasabi kung ano ang magiging resulta: maaaring magkapareho o magkaiba ang mga salita.

Ang hashCode()pamamaraan ay gumagana gamit ang isang katulad na prinsipyo. Kung tatawagin mo ito sa isang bagay, nagbabalik ito ng ilang numero — kahalintulad ng unang titik sa isang salita. Ang numerong ito ay may mga sumusunod na katangian:

  • Ang magkaparehong mga bagay ay palaging may parehong hashcode
  • Ang iba't ibang mga bagay ay maaaring magkaroon ng parehong hashcode, o ang kanilang mga hashcode ay maaaring magkaiba
  • Kung ang mga bagay ay may iba't ibang mga hashcode, kung gayon ang mga bagay ay tiyak na naiiba

Upang gawin itong mas malinaw, i-reframe natin ang mga katangiang ito sa mga tuntunin ng mga salita:

  • Ang mga magkatulad na salita ay palaging may parehong mga unang titik.
  • Ang iba't ibang salita ay maaaring magkaroon ng parehong mga unang titik, o ang kanilang mga unang titik ay maaaring magkaiba
  • Kung ang mga salita ay may iba't ibang mga unang titik, kung gayon ang mga salita ay tiyak na naiiba

Ang huling pag-aari ay ginagamit upang mapabilis ang paghahambing ng mga bagay:

Una, kinakalkula ang mga hashcode ng dalawang bagay. Kung ang mga hashcode na ito ay iba, kung gayon ang mga bagay ay tiyak na naiiba, at hindi na kailangang ihambing pa ang mga ito.

Ngunit kung pareho ang mga hashcode, kailangan pa rin nating ikumpara ang mga bagay gamit ang equals method.



6. Mga kontrata sa code

Ang pag-uugali na inilarawan sa itaas ay dapat ipatupad ng lahat ng mga klase sa Java. Sa panahon ng compilation, walang paraan upang suriin kung ang mga bagay ay inihambing nang tama.

Ang mga programmer ng Java ay may unibersal na kasunduan na kung isusulat nila ang kanilang sariling pagpapatupad ng equals() na pamamaraan at sa gayon ay i-override ang karaniwang pagpapatupad (sa Objectklase), dapat din nilang isulat ang kanilang sariling pagpapatupad ng hashCode()pamamaraan sa paraang ang mga nabanggit na panuntunan ay nasiyahan.

Ang kaayusan na ito ay tinatawag na kontrata .

Kung ipapatupad mo lamang ang equals()o ang pamamaraan lamang hashCode()sa iyong klase, kung gayon ikaw ay nasa matinding paglabag sa kontrata (nasira mo ang kasunduan). Huwag gawin ito.

Kung ginagamit ng ibang programmer ang iyong code, maaaring hindi ito gumana nang tama. Higit pa rito, gagamit ka ng code na umaasa sa pagsunod sa mga kontrata sa itaas.

Mahalaga!

Kapag naghahanap ng isang elemento, ang lahat ng mga koleksyon ng Java ay unang ihambing ang mga hashcode ng mga bagay, at pagkatapos ay magsagawa ng paghahambing gamit ang equalspamamaraan.

Nangangahulugan iyon na kung bibigyan mo ang iyong sariling klase ng isang equalspamamaraan ngunit hindi mo isinulat ang iyong sariling hashCode()pamamaraan o hindi mo ito ipinatupad nang tama, kung gayon ang mga koleksyon ay maaaring hindi gumana nang tama sa iyong mga bagay.

Halimbawa, maaari kang magdagdag ng isang bagay sa isang listahan at pagkatapos ay hanapin ito gamit ang contains()pamamaraan, ngunit maaaring hindi mahanap ng koleksyon ang iyong bagay.