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.
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. Kapag 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.
Sumasalungat 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.
GO TO FULL VERSION