JavaRush /Java Blog /Random-TK /deň we hashCode usullary: ulanmagyň amaly

deň we hashCode usullary: ulanmagyň amaly

Toparda çap edildi
Salam! Bu gün Java-da iki möhüm usul barada gürleşeris - equals()we hashCode(). Bu olar bilen ilkinji gezek duşuşanymyz däl: JavaRush kursunyň başynda gysga bir leksiýa bardy equals()- ýatdan çykaran bolsaňyz ýa-da öň görmedik bolsaňyz okaň. Usullar deňdir & amp;  hashCode: ulanyş amaly - 1Şu günki sapagymyzda bu düşünjeler barada jikme-jik gürleşeris - maňa ynanyň, gürleşmeli köp zat bar! Täze bir zada geçmezden ozal, ýatda saklan zatlarymyz barada ýadymyzy täzeläliň :) rememberadyňyzda bolsa, “ ==” ”operatoryny ulanýan iki obýektiň adaty deňeşdirilmegi erbet pikir, sebäbi“ ==”salgylanmalary deňeşdirýär. Ine, ýaňy-ýakynda geçirilen leksiýadan awtoulaglar bilen mysalymyz:
public class Car {

   String model;
   int maxSpeed;

   public static void main(String[] args) {

       Car car1 = new Car();
       car1.model = "Ferrari";
       car1.maxSpeed = 300;

       Car car2 = new Car();
       car2.model = "Ferrari";
       car2.maxSpeed = 300;

       System.out.println(car1 == car2);
   }
}
Konsol çykyşy:

false
Synpyň iki meňzeş obýektini döreden ýaly bolarys Car: iki maşyndaky meýdanlaryň hemmesi birmeňzeş, ýöne deňeşdirmegiň netijesi henizem ýalan. Munuň sebäbini eýýäm bilýäris: baglanyşyklar car1we car2ýatda dürli salgylary görkezýär, şonuň üçin deň däl. Biz henizem iki salgylanmany däl-de, iki zady deňeşdirmek isleýäris. Obýektleri deňeşdirmek üçin iň oňat çözgüt equals().

() usulyna deňdir

Bu usuly noldan döretmeýändigimizi ýadyňyzdan çykarmaň, ýöne ony ýok ediň - ahyrsoňy bu usul equals()synpda kesgitlenendir Object. Şeýle-de bolsa, adaty görnüşinde peýdasy az:
public boolean equals(Object obj) {
   return (this == obj);
}
equals()Usul synpda şeýle kesgitlenýär Object. Salgylary deňeşdirmek. Näme üçin beýle ýaradyldy? Dili döredijiler, programmaňyzdaky haýsy obýektleriň deň hasaplanýandygyny we haýsysynyň ýokdugyny nädip bilýärler? :) Bu usulyň esasy pikiri equals()- synpy döredijiniň özi bu synpyň obýektleriniň deňligini barlaýan aýratynlyklary kesgitleýär. equals()Şeýle etmek bilen, synpyňyzdaky usuly ýok edýärsiňiz . "Aýratynlyklary özüňiz kesgitleýärsiňiz" manysyna düşünmeseňiz, bir meselä seredeliň. Ine, ýönekeý bir adam synpy - Man.
public class Man {

   private String noseSize;
   private String eyesColor;
   private String haircut;
   private boolean scars;
   private int dnaCode;

public Man(String noseSize, String eyesColor, String haircut, boolean scars, int dnaCode) {
   this.noseSize = noseSize;
   this.eyesColor = eyesColor;
   this.haircut = haircut;
   this.scars = scars;
   this.dnaCode = dnaCode;
}

   //getters, setters, etc.
}
Iki adamyň ekizler bilen baglanyşyklydygyny ýa-da diňe doppelgängerdigini kesgitlemeli bir programma ýazýarys diýeliň. Bizde bäş aýratynlyk bar: burnuň ululygy, gözüň reňki, saç düzümi, yzlaryň bolmagy we DNK biologiki synagynyň netijeleri (ýönekeýligi üçin - kod belgisi görnüşinde). Siziň pikiriňizçe bu aýratynlyklaryň haýsysy programmamyza ekiz garyndaşlary kesgitlemäge mümkinçilik berer? Usullar deňdir & amp;  hashCode: ulanyş amaly - 2Elbetde, diňe biologiki synag kepillik berip biler. Iki adamyň gözüniň reňki, saç düzümi, burny we hatda yzlary bolup biler - dünýäde köp adam bar we tötänliklerden gaça durmak mümkin däl. Bize ygtybarly mehanizm gerek: diňe DNK synagynyň netijesi takyk netijä gelmäge mümkinçilik berýär. Bu biziň usulymyz üçin nämäni aňladýar equals()? ManMaksatnamamyzyň talaplaryny göz öňünde tutup, synpda täzeden kesgitlemeli . Usul iki obýektiň meýdanyny deňeşdirmeli int dnaCode, eger deň bolsa, obýektler deňdir.
@Override
public boolean equals(Object o) {
   Man man = (Man) o;
   return dnaCode == man.dnaCode;
}
Bu hakykatdanam ýönekeými? Aslynda beýle däl. Biz bir zady sypdyrdyk. Bu ýagdaýda, obýektlerimiz üçin deňligiň döredilen diňe bir “möhüm” meýdany kesgitledik dnaCode. Indi göz öňüne getiriň, bizde 1 däl, 50 sany şeýle “ähmiýetli” meýdan bar we iki obýektiň 50 meýdany deň bolsa, obýektler deňdir. Bu hem bolup biler. Esasy mesele, 50 meýdanyň deňligini hasaplamak köp wagt talap edýän we serişde talap edýän prosesdir. Indi göz öňüne getiriň, synpdan başga-da, edil öňki ýaly meýdanlary bolan Mansynpymyz bar . Başga bir programmist sapaklaryňyzy ulanýan bolsa, programmasynda aňsatlyk bilen bir zat ýazyp biler: WomanMan
public static void main(String[] args) {

   Man man = new Man(........); //a bunch of parameters in the constructor

   Woman woman = new Woman(.........);//same bunch of parameters.

   System.out.println(man.equals(woman));
}
Bu ýagdaýda meýdan bahalaryny barlamagyň manysy ýok: iki dürli synpyň obýektlerine seredýändigimizi görýäris we prinsipde deň bolup bilmeýärler! Bu, usulda equals()iki sany birmeňzeş synpyň obýektlerini deňeşdirmek üçin çek goýmalydygymyzy aňladýar. Bu hakda pikir edenimiz gowy zat!
@Override
public boolean equals(Object o) {
   if (getClass() != o.getClass()) return false;
   Man man = (Man) o;
   return dnaCode == man.dnaCode;
}
Maybeöne başga bir zady ýatdan çykardyk? Hmm ... Iň bolmanda, obýekti özi bilen deňeşdirmeýändigimizi barlamaly! A we B salgylanmalar ýatda şol bir adresi görkezýän bolsa, şol bir obýektdir, 50 meýdan bilen deňeşdirenimizde wagt ýitirmegimiz hem zerur däl.
@Override
public boolean equals(Object o) {
   if (this == o) return true;
   if (getClass() != o.getClass()) return false;
   Man man = (Man) o;
   return dnaCode == man.dnaCode;
}
Mundan başga-da, çek goşmak zyýany bolmaz null: hiç bir obýekt deň bolup bilmez null, bu ýagdaýda goşmaça barlaglaryň manysy ýok. Bularyň hemmesini göz öňünde tutup, equals()synp usulymyz Manşeýle bolar:
@Override
public boolean equals(Object o) {
   if (this == o) return true;
   if (o == null || getClass() != o.getClass()) return false;
   Man man = (Man) o;
   return dnaCode == man.dnaCode;
}
Aboveokarda agzalan başlangyç barlaglaryň hemmesini edýäris. Eger şeýle bolsa:
  • bir synpyň iki obýektini deňeşdirýäris
  • bu bir zat däl
  • obýektimiz bilen deňeşdiremzoknull
... soň möhüm aýratynlyklary deňeşdirmäge geçýäris. Biziň ýagdaýymyzda, dnaCodeiki obýektiň meýdanlary. Usuly ýok edende equals(), şu talaplary ýerine ýetiriň:
  1. Reflekslilik.

    equals()Islendik obýektiň özi bolmaly .
    Bu talaby eýýäm göz öňünde tutduk. Usulymyz şeýle diýýär:

    if (this == o) return true;

  2. Simmetriýa.

    Eger a.equals(b) == truebolsa, b.equals(a)gaýdyp gelmeli true.
    Usulymyz hem bu talaby kanagatlandyrýar.

  3. Geçiş.

    Iki jisim käbir üçünji jisime deň bolsa, onda biri-birine deň bolmaly.
    Eger a.equals(b) == truewe a.equals(c) == true, onda çek b.equals(c)hem dogry dolanmalydyr.

  4. Hemişelik.

    Işiň netijeleri equals()diňe oňa girizilen meýdanlar üýtgän mahaly üýtgemeli. Iki obýektiň maglumatlary üýtgemedik bolsa, barlagyň netijeleri equals()hemişe birmeňzeş bolmaly.

  5. Deňsizlik null.

    Islendik obýekt üçin çek a.equals(null)ýalňyş yzyna gaýtarylmaly.
    Bu diňe bir "peýdaly maslahatlaryň" toplumy däl, eýsem Oracle resminamalarynda görkezilen berk usul şertnamasydyr.

hashCode () usuly

Indi usul barada gürleşeliň hashCode(). Näme üçin zerur? Edil şol bir maksat üçin - obýektleri deňeşdirmek. Weöne bizde eýýäm bar equals()! Näme üçin başga usul? Jogap ýönekeý: öndürijiligi ýokarlandyrmak. Java-da, usul bilen aňladylýan hash funksiýasy hashCode(), islendik obýekt üçin kesgitlenen uzynlykdaky san bahasyny gaýtaryp berýär. Java ýagdaýynda bu usul hashCode()32 bitli görnüşi yzyna gaýtaryp berýär int. Iki sanlary biri-biri bilen deňeşdirmek, usuly ulanýan iki obýekti deňeşdirmekden has çalt equals(), esasanam köp meýdan ulanýan bolsa. Programmamyz obýektleri deňeşdirjek bolsa, muny hash kody bilen etmek has aňsat we diňe deň bolsa hashCode()- deňeşdirmäge dowam ediň equals(). Theeri gelende aýtsak, hash esasly maglumat gurluşlarynyň nähili işleýändigi, mysal üçin, bilýänleriňiz HashMap! Usul hashCode(), edil şonuň ýaly equals(), işläp düzüjiniň özi tarapyndan ýok edilýär. Edil şonuň ýaly equals(), bu usulyň hashCode()Oracle resminamalarynda görkezilen resmi talaplary bar:
  1. Iki obýekt deň bolsa (ýagny usul equals()hakyky gaýdyp gelýär), şol bir hash kody bolmaly.

    Otherwiseogsam usullarymyz manysyz bolar. Barlamagymyz hashCode(), aýdyşymyz ýaly, ilki bilen öndürijiligi gowulaşdyrmak üçin gelmeli. Haş kodlary başga bolsa, obýektler aslynda deň bolsa-da (usulda kesgitleýşimiz ýaly equals()) çek ýalan gaýdyp geler.

  2. Bir usul hashCode()şol bir obýektde birnäçe gezek çagyrylsa, her gezek şol bir belgini yzyna gaýtarmaly.

  3. 1-nji düzgün tersine işlemeýär. Iki dürli obýektiň hash kody bolup biler.

Üçünji düzgün birneme bulaşyk. Bu nädip bolup biler? Düşündiriş gaty ýönekeý. Usul hashCode()gaýdyp gelýär int. int32 bitli san. Onuň çäkli mukdary bar - -2,147,483,648-den +2,147,483,647-e çenli. Başgaça aýdylanda, sanyň bary-ýogy 4 milliarddan gowrak üýtgemegi bar int. Indi Eartherdäki ähli janly-jandarlar hakda maglumatlary saklamak üçin programma döredýändigiňizi göz öňüne getiriň. Her bir adamyň öz synp obýekti bolar Man. .5 7,5 milliard adam ýer ýüzünde ýaşaýar. Başgaça aýdylanda, Manobýektleri sanlara öwürmek üçin näçe algoritm ýazsak-da, ýeterlik san bolmaz. Bizde diňe 4,5 milliard wariant we başga-da köp adam bar. Diýmek, näçe synanyşsak-da, hash kodlary käbir dürli adamlar üçin birmeňzeş bolar. Bu ýagdaýa (iki dürli obýektiň gabat gelýän kodlary) çaknyşyk diýilýär. Bir usuly ýok edende programmistiň maksatlarynyň biri, hashCode()çaknyşyklaryň mümkin bolan sanyny mümkin boldugyça azaltmakdyr. Bu düzgünleriň hemmesini göz öňünde tutup, hashCode()synp üçin usulymyz nähili bolar ? ManŞuňa meňzeş:
@Override
public int hashCode() {
   return dnaCode;
}
Geň galdyňyzmy? :) Duýdansyz, ýöne talaplara seretseňiz, hemme zady ýerine ýetirýändigimizi görersiňiz. Biziňkileriň equals()hakykata gaýdýan obýektleri deň bolar hashCode(). Iki obýektimiziň Mangymmaty deň bolsa equals(ýagny şol bir gymmaty bar dnaCode), usulymyz şol bir belgini yzyna getirer. Has çylşyrymly bir meselä seredeliň. Maksatnamamyzyň kollektor müşderileri üçin kaşaň awtoulaglary saýlamalydygyny aýdalyň. Ectingygnamak çylşyrymly zat we oňa köp aýratynlyklar bar. 1963-nji ýyldaky awtoulag 1964-nji ýyldaky awtoulagdan 100 esse gymmat bolup biler. 1970-nji ýyldaky gyzyl awtoulag, şol ýylky gök awtoulagdan 100 esse gymmat bolup biler. Usullar deňdir & amp;  hashCode: ulanyş amaly - 4Birinji ýagdaýda, synp bilen Manmeýdanlaryň köpüsini (ýagny adam häsiýetleri) ähmiýetsiz taşladyk we deňeşdirmek üçin diňe meýdany ulandyk dnaCode. Bu ýerde gaty üýtgeşik bir sfera bilen işleýäris, ujypsyz jikme-jiklikler bolup bilmez! Ine, biziň synpymyz LuxuryAuto:
public class LuxuryAuto {

   private String model;
   private int manufactureYear;
   private int dollarPrice;

   public LuxuryAuto(String model, int manufactureYear, int dollarPrice) {
       this.model = model;
       this.manufactureYear = manufactureYear;
       this.dollarPrice = dollarPrice;
   }

   //... getters, setters, etc.
}
Bu ýerde deňeşdirenimizde ähli ugurlary göz öňünde tutmalydyrys. Islendik ýalňyşlyk müşderi üçin ýüzlerçe müň dollar töläp biler, şonuň üçin howpsuz bolmak has gowudyr:
@Override
public boolean equals(Object o) {
   if (this == o) return true;
   if (o == null || getClass() != o.getClass()) return false;

   LuxuryAuto that = (LuxuryAuto) o;

   if (manufactureYear != that.manufactureYear) return false;
   if (dollarPrice != that.dollarPrice) return false;
   return model.equals(that.model);
}
Usulymyzda, equals()ozal gürleşen ähli barlaglarymyzy ýatdan çykarmadyk. Emma indi obýektlerimiziň üç meýdanynyň hersini deňeşdirýäris. Bu programmada deňlik mutlak bolmaly, her ugurda. Näme hakda hashCode?
@Override
public int hashCode() {
   int result = model == null ? 0 : model.hashCode();
   result = result + manufactureYear;
   result = result + dollarPrice;
   return result;
}
Biziň synpymyzdaky meýdan modelsetir. Bu amatly: synpda eýýäm Stringusul ýok edildi. hashCode()Meýdanyň hash koduny hasaplaýarys modelwe oňa beýleki iki san meýdanynyň jemini goşýarys. Java-da çaknyşyklaryň sanyny azaltmak üçin ulanylýan birneme mekirlik bar: hash koduny hasaplanyňyzda aralyk netijäni täsin san bilen köpeldiň. Iň köp ulanylýan san 29 ýa-da 31-dir. Häzirki wagtda matematikanyň jikme-jikliklerine girip bilmeris, ýöne geljekde salgylanmak üçin aralyk netijeleri ýeterlik mukdarda köpeltmek hashiň netijelerini “ýaýratmaga” kömek edýändigini ýadyňyzdan çykarmaň. işleýär we şol bir hashcode bilen has az obýekt bilen gutarýar. “LuxuryAuto” -daky usulymyz üçin hashCode()şeýle bolar:
@Override
public int hashCode() {
   int result = model == null ? 0 : model.hashCode();
   result = 31 * result + manufactureYear;
   result = 31 * result + dollarPrice;
   return result;
}
Bu mehanizmiň ähli jikme-jiklikleri barada has giňişleýin maglumaty StackOverflow-daky ýazgyda , şeýle hem Joşua Bloçyň “ Netijeli Java ” kitabynda okap bilersiňiz . Ahyrynda bellemeli ýene bir möhüm nokat bar. Her gezek artykmaç ýazylanda equals(), hashCode()bu usullarda göz öňünde tutulan obýektiň käbir meýdanlaryny saýlaýardyk. equals()Inöne dürli ugurlary göz öňünde tutup bilerismi hashCode()? Tehniki taýdan edip bileris. Thisöne bu erbet pikir we şu sebäpden:
@Override
public boolean equals(Object o) {
   if (this == o) return true;
   if (o == null || getClass() != o.getClass()) return false;

   LuxuryAuto that = (LuxuryAuto) o;

   if (manufactureYear != that.manufactureYear) return false;
   return dollarPrice == that.dollarPrice;
}

@Override
public int hashCode() {
   int result = model == null ? 0 : model.hashCode();
   result = 31 * result + manufactureYear;
   result = 31 * result + dollarPrice;
   return result;
}
Ine, “LuxuryAuto” synpy equals()üçin usullarymyz . hashCode()Usul hashCode()üýtgemedi we equals()meýdançany usuldan aýyrdyk model. Indi model iki zady deňeşdirmek üçin häsiýetli däl equals(). Emma hash koduny hasaplanda henizem göz öňünde tutulýar. Netijede näme alarys? Iki maşyn döredeliň we barlap göreliň!
public class Main {

   public static void main(String[] args) {

       LuxuryAuto ferrariGTO = new LuxuryAuto("Ferrari 250 GTO", 1963, 70000000);
       LuxuryAuto ferrariSpider = new LuxuryAuto("Ferrari 335 S Spider Scaglietti", 1963, 70000000);

       System.out.println("Are these two objects equal to each other?");
       System.out.println(ferrariGTO.equals(ferrariSpider));

       System.out.println("What are their hash codes?");
       System.out.println(ferrariGTO.hashCode());
       System.out.println(ferrariSpider.hashCode());
   }
}

Эти два an object равны друг другу?
true
Какие у них хэш-codeы?
-1372326051
1668702472
Roralňyşlyk! Dürli meýdanlary ulanyp equals(), hashCode()olar üçin döredilen şertnamany bozduk! Iki sany deň equals()obýektiň hash kody bolmaly. Biz olar üçin dürli many aldyk. Şeýle ýalňyşlyklar, esasanam heşleri ulanýan kolleksiýalar bilen işleýän wagtyňyz iň ajaýyp netijelere sebäp bolup biler. Şonuň üçin täzeden kesgitlenende equals()we hashCode()şol meýdanlary ulanmak dogry bolar. Leksiýa gaty uzyn boldy, ýöne bu gün köp täze zatlar öwrendiňiz! :) Meseleleri çözmäge gaýdyp gelmegiň wagty geldi!
Teswirler
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION