JavaRush /Java Blog /Random-TL /Coffee break #168. Bakit i-override ang mga katumbas at h...

Coffee break #168. Bakit i-override ang mga katumbas at hashcode na pamamaraan sa Java?

Nai-publish sa grupo

Bakit i-override ang mga katumbas at hashcode na pamamaraan sa Java?

Source: Medium Nakatuon ang artikulong ito sa dalawang malapit na nauugnay na pamamaraan: equals() at hashcode() . Malalaman mo kung paano sila nakikipag-ugnayan sa isa't isa at kung paano i-override ang mga ito nang tama. Coffee break #168.  Bakit i-override ang mga katumbas at hashcode na pamamaraan sa Java?  - 1

Bakit natin i-override ang equals() na pamamaraan?

Sa Java, hindi namin mai-overload ang pag-uugali ng mga operator tulad ng == , += , -+ . Gumagana sila ayon sa isang naibigay na proseso. Halimbawa, isaalang-alang ang pagpapatakbo ng == operator .

Paano gumagana ang == operator?

Sinusuri nito kung ang dalawang sanggunian na inihambing ay tumuturo sa parehong halimbawa sa memorya. Ang == operator ay magsusuri lamang sa true kung ang dalawang reference ay kumakatawan sa parehong halimbawa sa memorya. Tingnan natin ang sample code:
public class Person {
      private Integer age;
      private String name;

      ..getters, setters, constructors
      }
Sabihin nating sa iyong programa ay nakagawa ka ng dalawang Person object sa magkaibang lugar at gusto mong ikumpara ang mga ito.
Person person1 = new Person("Mike", 34);
Person person2 = new Person("Mike", 34);
System.out.println( person1 == person2 ); --> will print false!
From a business perspective, pareho ang itsura ng dalawa, di ba? Ngunit para sa JVM hindi sila pareho. Dahil pareho silang nilikha gamit ang bagong keyword , ang mga pagkakataong ito ay matatagpuan sa iba't ibang mga segment ng memorya. Samakatuwid ang == operator ay magbabalik ng false . Ngunit kung hindi natin ma-override ang == operator , kung gayon paano natin sasabihin sa JVM na gusto nating ang dalawang bagay na ito ay tratuhin nang pareho? Dito pumapasok ang pamamaraang .equals() . Maaari mong i-override ang equals() upang suriin kung ang ilang mga bagay ay may parehong mga halaga para sa ilang mga patlang upang isaalang-alang ang mga ito na pantay. Maaari mong piliin kung aling mga field ang ihahambing. Kung sasabihin natin na ang dalawang Person object ay magiging pareho lamang kung mayroon silang parehong edad at parehong pangalan, kung gayon ang IDE ay bubuo ng isang bagay na tulad nito upang awtomatikong lumikha ng equals() :
@Override
public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                name.equals(person.name);
    }
Bumalik tayo sa dati nating halimbawa.
Person person1 = new Person("Mike", 34);
Person person2 = new Person("Mike", 34);
System.out.println ( person1 == person2 ); --> will print false!
System.out.println ( person1.equals(person2) ); --> will print true!
Oo, hindi namin ma-overload ang == operator upang ihambing ang mga bagay sa paraang gusto namin, ngunit binibigyan kami ng Java ng isa pang paraan - ang equals() method , na maaari naming i-override ayon sa gusto namin. Tandaan na kung hindi namin ibibigay ang aming custom na bersyon ng .equals() (kilala rin bilang override) sa aming klase, ang paunang natukoy na .equals() mula sa Object class at ang == operator ay magiging pareho. Ang default na equals() na pamamaraan , na minana mula sa Object , ay susuriin kung ang parehong mga pagkakataon na inihambing ay pareho sa memorya!

Bakit natin ino-override ang hashCode() na pamamaraan?

Ang ilang istruktura ng data sa Java, gaya ng HashSet at HashMap , ay nag-iimbak ng kanilang mga elemento batay sa isang hash function na inilalapat sa mga elementong iyon. Ang hash function ay hashCode() . Kung mayroon tayong pagpipilian sa pag-override sa .equals() method , dapat din tayong magkaroon ng pagpipilian sa pag-override sa hashCode() method . May dahilan para dito. Pagkatapos ng lahat, ang default na pagpapatupad ng hashCode() , na minana mula sa Object , ay itinuturing na natatangi ang lahat ng mga bagay sa memorya! Ngunit bumalik tayo sa mga istruktura ng hash data na ito. Mayroong panuntunan para sa mga istruktura ng data na ito. Ang isang HashSet ay hindi maaaring maglaman ng mga duplicate na halaga at ang isang HashMap ay hindi maaaring maglaman ng mga duplicate na key. Ang isang HashSet ay ipinatupad gamit ang isang HashMap sa paraang ang bawat HashSet value ay nakaimbak bilang isang susi sa HashMap . Paano gumagana ang HashMap ? Ang HashMap ay isang katutubong hanay na may maraming mga segment. Ang bawat segment ay may naka-link na listahan ( linkedList ). Iniimbak ng naka-link na listahang ito ang aming mga susi. Hinahanap ng HashMap ang tamang linkedList para sa bawat key gamit ang hashCode() method , at pagkatapos ay inuulit ang lahat ng elemento ng linkedList na iyon at inilalapat ang equals() na paraan sa bawat isa sa mga elementong iyon upang suriin kung ang elementong iyon ay nakapaloob doon. Hindi pinapayagan ang mga duplicate na key. Coffee break #168.  Bakit i-override ang mga katumbas at hashcode na pamamaraan sa Java?  - 2Kapag naglagay kami ng isang bagay sa loob ng isang HashMap , ang susi ay nakaimbak sa isa sa mga naka-link na listahang ito. Aling naka-link na listahan ang itatabi ng key na ito ay ipinapakita ng resulta ng hashCode() method para sa key na iyon. Iyon ay, kung ang key1.hashCode() ay magreresulta sa 4, ang key1 na iyon ay maiimbak sa ika-4 na segment ng array sa LinkedList na umiiral doon . Bilang default, ang hashCode() na paraan ay nagbabalik ng iba't ibang resulta para sa bawat pagkakataon. Kung mayroon tayong default na equals() na kumikilos tulad ng == , na tinatrato ang lahat ng mga pagkakataon sa memorya bilang iba't ibang mga bagay, kung gayon walang magiging problema. Kung maaalala mo, sa aming nakaraang halimbawa, sinabi namin na gusto naming ang mga pagkakataon ng Tao ay ituring na pantay-pantay kung magkapareho ang kanilang mga edad at pangalan.
Person person1 = new Person("Mike", 34);
    Person person2 = new Person("Mike", 34);
    System.out.println ( person1.equals(person2) );  --> will print true!
Ngayon, gumawa tayo ng mapa upang iimbak ang mga pagkakataong ito bilang mga key na may partikular na string bilang pares ng halaga.
Map<Person, String> map = new HashMap();
map.put(person1, "1");
map.put(person2, "2");
Sa klase ng Tao , hindi namin na-override ang hashCode method , ngunit mayroon kaming overridden equals method . Dahil ang default na hashCode ay nagbibigay ng iba't ibang resulta para sa iba't ibang Java instance ng person1.hashCode() at person2.hashCode() , may mataas na pagkakataong makakuha ng iba't ibang resulta. Ang aming mapa ay maaaring magtapos sa iba't ibang tao sa iba't ibang naka-link na listahan. Coffee break #168.  Bakit i-override ang mga katumbas at hashcode na pamamaraan sa Java?  - 3Sumasalungat ito sa lohika ng HashMap . Pagkatapos ng lahat, ang isang HashMap ay hindi maaaring magkaroon ng maraming magkakaparehong mga susi! Ang punto ay ang default na hashCode() na minana mula sa klase ng Object ay hindi sapat. Kahit na pagkatapos nating i-override ang equals() na pamamaraan ng klase ng Tao . Iyon ang dahilan kung bakit kailangan nating i-override ang hashCode() method pagkatapos nating i-override ang equals method . Ngayon ayusin natin ito. Kailangan naming i-override ang aming hashCode() na paraan upang isaalang-alang nito ang parehong mga field bilang equals() , lalo na ang edad at pangalan .
public class Person {
      private Integer age;
      private String name;

      ..getters, setters, constructors
@Override
public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                name.equals(person.name);
    }
@Override
public int hashCode() {
        int prime = 31;
        return prime*Objects.hash(name, age);
    }
Sa pamamaraan ng hashCode() gumamit kami ng isang simpleng halaga (maaari kang gumamit ng anumang iba pang mga halaga). Gayunpaman, iminumungkahi na gumamit ng mga pangunahing numero upang lumikha ng mas kaunting mga problema. Subukan nating iimbak muli ang mga key na ito sa ating HashMap :
Map<Person, String> map = new HashMap();
map.put(person1, "1");
map.put(person2, "2");
Magiging pareho ang person1.hashCode() at person2.hashCode() . Sabihin nating sila ay 0. Ang HashMap ay mapupunta sa segment 0 at sa loob nito ang LinkedList ay magse-save ng person1 bilang isang susi na may halagang "1". Sa pangalawang kaso, kapag ang HashMap ay pumunta sa bucket 0 muli upang iimbak ang key person2 na may halagang "2", makikita nito na mayroon nang isa pang key na katumbas nito. Sa ganitong paraan, ma-overwrite nito ang nakaraang key. At tanging ang pangunahing person2 lang ang iiral sa aming HashMap . Ito ay kung paano namin natutunan kung paano gumagana ang panuntunan ng HashMap , na nagsasaad na hindi ka maaaring gumamit ng maraming magkakaparehong key! Gayunpaman, tandaan na ang hindi pantay na mga instance ay maaaring magkaroon ng parehong hashcode, at ang mga pantay na instance ay dapat magbalik ng parehong hashcode.Coffee break #168.  Bakit i-override ang mga katumbas at hashcode na pamamaraan sa Java?  - 4
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION