JavaRush /Java Blog /Random-TK /Deňdir we hashCode şertnamalary ýa-da näme bolsa
Aleksandr Zimin
Dereje
Санкт-Петербург

Deňdir we hashCode şertnamalary ýa-da näme bolsa

Toparda çap edildi
Elbetde, Java programmistleriniň aglaba köplügi usullaryň biri-biri bilen ýakyndan equalsbaglanyşyklydygyny hashCodewe bu usullaryň ikisini-de sapaklarynda yzygiderli ýok etmegiň maslahat berilýändigini bilýärler. Birneme az sanly adam munuň näme üçin beýle bolýandygyny we bu düzgün bozulsa nähili gynandyryjy netijeleriň bolup biljekdigini bilýär. Bu usullaryň düşünjesini gözden geçirmegi, maksadyny gaýtalamagy we näme üçin beýle baglanyşýandygyna düşünmegi teklip edýärin. Bu makalany, meseläniň ähli jikme-jikliklerini aýan etmek we indi üçünji tarap çeşmelerine gaýdyp gelmezlik üçin, sapaklary ýüklemek baradaky öňki ýaly bolşy ýaly ýazdym. Şonuň üçin konstruktiw tankyt etmekden hoşal bolaryn, sebäbi bir ýerde boşluklar bar bolsa, olary ýok etmeli. Makala, gaty uzyn bolup çykdy.

ýok etmek düzgünlerine deňdir

Java-da bir gelip çykyşy bolan iki obýektiň logiki taýdan deňdigini tassyklamak ýa-da inkär etmek üçin bir usul equals()gerek . Twoagny, iki obýekti deňeşdireniňde, programmist olaryň möhüm meýdanlarynyň deňdigine ýa-da ýokdugyna düşünmeli . Fieldshli meýdanlaryň birmeňzeş bolmagy hökman däl, sebäbi usul logiki deňligi göz öňünde tutýar . Emma käwagt bu usuly ulanmagyň aýratyn zerurlygy ýok. Aýdyşlary ýaly, belli bir mehanizmi ulanmak bilen kynçylyklardan gaça durmagyň iň aňsat usuly ony ulanmazlykdyr. Şertnamany bozanyňyzdan soň, beýleki obýektleriň we gurluşlaryň obýektiňiz bilen nähili täsirleşjekdigine düşünip bilmejekdigiňizi hem bellemelidiris . Soň bolsa ýalňyşlygyň sebäbini tapmak gaty kyn bolar. equals()equals

Haçan-da bu usuly ýok etmeli däl

  • Haçan-da synpyň her mysaly özboluşly bolsa.
  • Has köp derejede, bu maglumatlar bilen işlemek üçin däl-de, belli bir özüni alyp barşy üpjün edýän synplara degişlidir. Mysal üçin, synp ýaly Thread. Olar üçin equalssynp tarapyndan berlen usulyň durmuşa geçirilmegi Objectýeterlik däl. Başga bir mysal, enum synplary ( Enum).
  • Aslynda synp öz ýagdaýlarynyň ekwiwalentligini kesgitlemek talap edilmeýär.
  • Mysal üçin, synp üçin java.util.Randomsynplaryň mysallaryny biri-biri bilen deňeşdirip, tötänleýin sanlaryň birmeňzeş yzygiderliligini yzyna gaýtaryp biljekdigini kesgitlemek zerurlygy ýok. Diňe bu synpyň tebigaty beýle hereketi aňlatmaýar.
  • Giňeldýän synpyňyzda eýýäm usulyň ýerine ýetirilişi bar equalswe bu ýerine ýetirişiň özüni alyp barşy size laýyk gelýär.
  • Mysal üçin, synplar Setüçin ýerine ýetiriş we Listdegişlilikde . MapequalsAbstractSetAbstractListAbstractMap
  • Netijede, equalssynpyňyzyň gerimi privateýa package-private-da bu usulyň hiç haçan çagyrylmajakdygyna ynanýarsyňyz.

şertnamasyna deňdir

Usuly ýok edende, equalsdörediji Java dil spesifikasiýasynda kesgitlenen esasy düzgünleri berjaý etmeli.
  • Reflekslilik
  • islendik baha üçin xaňlatma x.equals(x)gaýdyp gelmeli true.
    Berildi - munuň manysyx != null
  • Simmetriýa
  • berlen bahalar üçin xwe ydiňe gaýdyp gelse x.equals(y)gaýdyp gelmeli . truey.equals(x)true
  • Geçiş
  • berlen bahalar üçin , xwe ygaýdyp gelse z, bahany yzyna gaýtarmaly . x.equals(y)truey.equals(z)truex.equals(z)true
  • Yzygiderlilik
  • berlen bahalar üçin xwe ygaýtalanýan jaň , x.equals(y)iki obýekti deňeşdirmek üçin ulanylýan meýdanlar jaňlaryň arasynda üýtgemese, öňki jaňyň bahasyny şu usula gaýtaryp berer.
  • Deňeşdirme null
  • islendik baha üçin xjaň x.equals(null)gaýdyp gelmeli false.

şertnamanyň bozulmagyna deňdir

Java kolleksiýalarynyň çarçuwasy ýaly köp synplar usulyň durmuşa geçirilmegine baglydyr equals(), şonuň üçin ony äsgermezlik etmeli däl, sebäbi Bu usulyň şertnamasynyň bozulmagy programmanyň manysyz işlemegine sebäp bolup biler we bu ýagdaýda sebäbini tapmak gaty kyn bolar. Reflekslilik ýörelgesine görä , her bir jisim özüne deň bolmaly. Bu ýörelge bozulan bolsa, kolleksiýa bir zat goşup, ony usul bilen gözlänimizde, contains()kolleksiýa ýaňy goşan zadymyzy tapyp bilmeris. Simmetriýa şerti , haýsy iki obýektiň deňeşdirilendigine garamazdan deň bolmalydygyny aýdýar. equalsMysal üçin, diňe bir görnüşli setir görnüşini öz içine alýan synpyňyz bar bolsa, bu meýdany usul bilen setir bilen deňeşdirmek nädogry bolar . Sebäbi ters deňeşdirme bolan ýagdaýynda usul hemişe bahany yzyna gaýtaryp berer false.
// Нарушение симметричности
public class SomeStringify {
    private String s;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o instanceof SomeStringify) {
            return s.equals(((SomeStringify) o).s);
        }
        // нарушение симметричности, классы разного происхождения
        if (o instanceof String) {
            return s.equals(o);
        }
        return false;
    }
}
//Правильное определение метода equals
@Override
public boolean equals(Object o) {
    if (this == o) return true;
    return o instanceof SomeStringify &&
            ((SomeStringify) o).s.equals(s);
}
Geçiş ýagdaýyndan üç jisimiň ikisi deň bolsa, bu ýagdaýda üçüsi hem deň bolmaly diýilýär. Belli bir esasy synpy oňa manyly komponent goşmak bilen giňeltmek zerur bolanda bu ýörelgäni aňsatlyk bilen bozup bolar . PointMysal üçin, koordinatlar bilen bir klasa xwe ynokadyň reňkini giňeltmek bilen goşmaly. ColorPointMunuň üçin degişli meýdan bilen synp yglan etmeli bolarsyňyz color. Şeýlelik bilen, giňeldilen synpda ene-atanyň usuly diýýäris we ene-atada diňe koordinatlar we deňeşdirilýär equalsdiýip çaklaýarys , onda dürli reňkli, ýöne birmeňzeş koordinatlar bilen iki nokat deň hasap ediler, bu nädogry. Bu ýagdaýda alnan synpy reňkleri tapawutlandyrmagy öwretmek zerurdyr. Munuň üçin iki usuly ulanyp bilersiňiz. Emma biri simmetriýanyň düzgünini , ikinjisi - geçişliligini bozar . xy
// Первый способ, нарушая симметричность
// Метод переопределен в классе ColorPoint
@Override
public boolean equals(Object o) {
    if (!(o instanceof ColorPoint)) return false;
    return super.equals(o) && ((ColorPoint) o).color == color;
}
Bu ýagdaýda jaň point.equals(colorPoint)gymmaty yzyna getirer truewe deňeşdirme colorPoint.equals(point)gaýdyp geler false, sebäbi “synp” obýektine garaşýar. Şeýlelik bilen simmetriýanyň düzgüni bozulýar. Ikinji usul, nokadyň reňki barada maglumat ýok bolsa, ýagny synpymyz bar bolsa, "kör" barlagy öz içine alýar Point. Ora-da bu hakda maglumat bar bolsa, reňkini barlaň, ýagny synpyň obýektini deňeşdiriň ColorPoint.
// Метод переопределен в классе ColorPoint
@Override
public boolean equals(Object o) {
    if (!(o instanceof Point)) return false;

    // Слепая проверка
    if (!(o instanceof ColorPoint))
        return super.equals(o);

    // Полная проверка, включая цвет точки
    return super.equals(o) && ((ColorPoint) o).color == color;
}
Geçiş ýörelgesi şu ýerde aşakdaky ýaly bozulýar. Aşakdaky obýektleriň kesgitlemesi bar diýeliň:
ColorPoint p1 = new ColorPoint(1, 2, Color.RED);
Point p2 = new Point(1, 2);
ColorPoint p3 = new ColorPoint(1, 2, Color.BLUE);
Şeýlelik bilen, deňlik p1.equals(p2)we kanagatly bolsa-da p2.equals(p3), p1.equals(p3)gymmaty yzyna getirer false. Şol bir wagtyň özünde, ikinji usul, meniň pikirimçe, az özüne çekiji görünýär, sebäbi Käbir hadysalarda algoritm kör bolup, deňeşdirmäni doly ýerine ýetirip bilmez we bu hakda bilmezligiňiz mümkin. Biraz goşgy Umuman, düşünşim ýaly, bu meseläniň anyk çözgüdi ýok. Keý Horstmann atly bir abraýly ýazyjynyň pikirine görä, operatoryň ulanylyşyny obýektiň synpyny yzyna gaýtarýan instanceofusul jaňy bilen çalşyp bilersiňiz getClass()we obýektleriň özlerini deňeşdirip başlamazdan ozal olaryň birmeňzeşdigine göz ýetiriň. we umumy gelip çykyşyna üns bermäň. Şeýlelik bilen, simmetriýanyň we geçiş düzgünleri kanagatlandyrylar. Emma şol bir wagtyň özünde, barrikadanyň beýleki tarapynda giň çemeleşmelerde hormat goýulmaýan başga bir ýazyjy Joşua Bloç dur, bu çemeleşme Barbara Liskowyň ornuny tutýar diýip hasaplaýar. Bu ýörelge , "çagyryş kody esasy synpy bilmän, öz kiçi klaslary ýaly garamalydyr " diýilýär . Horstmann tarapyndan teklip edilen çözgütde bu ýörelge aç-açan bozulýar, sebäbi durmuşa geçirilmegine bagly. Gysgaça aýdylanda, meseläniň garaňkydygy aýdyňdyr. Şeýle hem Horstmanyň çemeleşmesini ulanmagyň düzgünini aýdyňlaşdyrýandygyny we sapaklary düzeniňizde strategiýa barada karar bermelidigiňizi we iňlis dilinde aç-açan ýazýandygyny, deňlik synagy diňe superklass tarapyndan geçiriljek bolsa, muny ýerine ýetirip bilersiňiz operasiýa instanceof. Otherwiseogsam, alnan synplara we usulyň ýerine ýetirilişine baglylykda barlagyň semantikasy üýtgese, usuly ulanmaly getClass(). ColorPointJoşua Bloç hem öz gezeginde mirasa ýüz öwürmegi we synpyň içine bir synp goşmak we bu nokat barada ýörite maglumat almak üçin Pointgiriş usulyny bermek arkaly obýektiň düzümini ulanmagy teklip edýär . asPoint()Bu, ähli düzgünleri bozmakdan gaça durar, ýöne, meniň pikirimçe, kody düşünmek has kynlaşdyrar. Üçünji wariant, IDE ulanyp, deň usulyň awtomatiki öndürilmegini ulanmak. Ideaeri gelende aýtsak, ideýa superklasda ýa-da onuň nesillerinde usuly durmuşa geçirmegiň strategiýasyny saýlamaga mümkinçilik berýän Horstmann neslini köpeldýär. Netijede, indiki yzygiderlilik düzgüni , obýektler üýtgemese-de x, yolary täzeden çagyrmak x.equals(y)öňküsi ýaly bahany yzyna gaýtarmalydygyny aýdýar. Iň soňky düzgün, hiç bir obýektiň deň bolmazlygydyr null. Bu ýerde hemme zat düşnükli null- bu näbellilik, obýekt näbellilige deňmi? Bu düşnükli däl false.

Deňligi kesgitlemek üçin umumy algoritm

  1. thisObýekt salgylanmalarynyň we usul parametrleriniň deňligini barlaň o.
    if (this == o) return true;
  2. Baglanyşygyň kesgitlenendigini oýa-da ýokdugyny barlaň null.
    Geljekde obýektiň görnüşlerini deňeşdireniňde, operator ulanylar instanceof, bu element geçip biler, sebäbi bu parametr falsebu ýagdaýda gaýdyp gelýär null instanceof Object.
  3. Aboveokardaky düşündirişe we öz duýgurlygyňyza esaslanýan operator ýa-da usul thisulanyp , obýekt görnüşlerini deňeşdiriň .oinstanceofgetClass()
  4. Bir usul equalskiçi klasda ýok edilse, jaň ediňsuper.equals(o)
  5. Parametr görnüşini ozerur klasa öwüriň.
  6. Significanthli möhüm obýekt meýdanlaryny deňeşdiriň:
    • operatory ulanyp, başlangyç görnüşler üçin ( floatwe başga)double==
    • salgylanma meýdanlary üçin olaryň usulyna jaň etmeliequals
    • massiwler üçin siklik gaýtalama ýa-da usul ulanyp bilersiňizArrays.equals()
    • görnüşleri üçin floatwe doubledegişli örtük synplarynyň deňeşdirme usullaryny ulanmaly Float.compare()weDouble.compare()
  7. Netijede, üç soraga jogap beriň: ýerine ýetirilen usul simmetrikmi ? Geçişmi ? Ylalaşdyňyzmy ? Beýleki iki ýörelge ( reflekslilik we ynam ) adatça awtomatiki usulda amala aşyrylýar.

HashCode düzgünleri ýok edýär

Haş, belli bir wagtda ýagdaýyny suratlandyrýan obýektden emele gelen san. Bu san Java ýaly esasan hash tablisalarynda ulanylýar HashMap. Bu ýagdaýda, obýekte esaslanýan san almagyň hash funksiýasy, hash tablisasynyň üstünde elementleriň deňeşdirip paýlanmagyny üpjün etmek üçin durmuşa geçirilmelidir. Şeýle hem, funksiýa dürli düwmeler üçin birmeňzeş bahany yzyna gaýtarsa, çaknyşmak ähtimallygyny azaltmak.

Şertnama hashCode

Haş funksiýasyny ýerine ýetirmek üçin dil spesifikasiýasy aşakdaky düzgünleri kesgitleýär:
  • usuly hashCodeşol bir obýektde bir ýa-da birnäçe gezek çagyrmak, bahany hasaplamaga gatnaşýan obýektleriň meýdanlary üýtgemese, şol bir hash bahasyny yzyna gaýtarmalydyr.
  • iki obýektde usuly çagyrmak, hashCodeobýektler deň bolsa, hemişe şol bir belgini yzyna gaýtarmaly ( equalsbu obýektlere usuly çagyrmak gaýdyp gelýär true).
  • hashCodeiki sany deň bolmadyk obýektde usul çagyrmak, dürli hash bahalaryny yzyna gaýtarmaly. Bu talap hökmany bolmasa-da, ýerine ýetirilişiniň hash tablisalarynyň işine oňyn täsir etjekdigini göz öňünde tutmalydyrys.

Deňdir we hashCode usullary bilelikde ýok edilmeli

Aboveokarda beýan edilen şertnamalara esaslanyp, koduňyzdaky usuly ýok edende equals, usuly elmydama ýok etmeli bolarsyňyz hashCode. Aslynda synpyň iki mysaly dürli ýat ýerlerinde bolany üçin dürli-dürli bolansoň, käbir logiki ölçeglere görä deňeşdirilmeli. Şoňa laýyklykda iki logiki taýdan ekwiwalent obýekt şol bir hash bahasyny yzyna gaýtarmaly. Bu usullaryň diňe biri ýok edilse näme bolar?
  1. equalsHawa hashCodeÝok

    equalsSynpymyzda bir usuly dogry kesgitledik we hashCodeusuly synpdaky ýaly goýmagy makul bildik Object. Soňra usulyň nukdaýnazaryndan equalsiki obýekt logiki taýdan deň bolar, usulyň nukdaýnazaryndan hashCodeumumylyk bolmaz. Şeýlelik bilen, bir zady hash tablisasyna ýerleşdirip, ony açar bilen yzyna almazlyk howpuny başdan geçirýäris.
    Mysal üçin, şuňa meňzeş:

    Map<Point, String> m = new HashMap<>();
    m.put(new Point(1, 1),Point A);
    // pointName == null
    String pointName = m.get(new Point(1, 1));

    Elbetde, ýerleşdirilýän obýekt we gözlenýän obýekt logiki taýdan deň bolsa-da, iki dürli obýektdir. Emma, ​​sebäbi şertnamany bozanymyz üçin dürli hash bahalary bar, heş tablisasynyň içegesinde bir zadymyzy ýitirendigimizi aýdyp bileris.

  2. hashCodeHawa equalsÝok.

    Usuly ýok etsek hashCodewe equalsusulyň ýerine ýetirilişini synpdan miras alsak näme bolýar Object. Bilşiňiz ýaly, equalsdeslapky usul görkezijileri obýektler bilen deňeşdirýär we olaryň şol bir obýekte degişlidigini kesgitleýär. Usuly ähli kanonlara laýyklykda ýazdyk hashCode, ýagny IDE ulanyp döreddik we logiki taýdan birmeňzeş obýektler üçin şol bir hash bahalaryny yzyna gaýtaryp bereliň. Elbetde, şeýle etmek bilen eýýäm iki jisimi deňeşdirmegiň käbir mehanizmini kesgitledik.

    Şonuň üçin öňki abzasdan mysal teoriýa boýunça amala aşyrylmalydyr. Stillöne henizem hash tablisasynda obýektimizi tapyp bilmeris. Muňa ýakyn bolsak-da, iň bolmanda obýektiň ýatjak hash stol sebedini taparys.

    Haş tablisasyndaky obýekti üstünlikli gözlemek üçin, açaryň hash bahalaryny deňeşdirmekden başga-da, gözlenýän obýekt bilen açaryň logiki deňligini kesgitlemek hem ulanylýar. .Agny, equalsusuly ýok etmezden hiç hili ýol ýok.

HashCode kesgitlemek üçin umumy algoritm

Ine, meniň pikirimçe, gaty köp alada etmeli däl we halaýan IDE-de usuly döretmeli däl. Sebäbi altyn gatnaşygy gözlemek üçin sag we çepe bitleriň bu üýtgemegi, adaty paýlanyş - bu düýbünden birkemsiz dudlar üçin. Özüm, şol bir ideýadan has gowy we has çalt edip biljekdigime şübhelenýärin.

Netijäniň ýerine

Şeýlelik bilen, usullaryň Java dilinde gowy kesgitlenen rol equalsoýnaýandygyny we iki obýektiň logiki deňligini almak üçin döredilendigini görýäris . hashCodeUsul meselesinde equalsmunuň obýektleri deňeşdirmek bilen gönüden-göni baglanyşygy bar, hashCodegytaklaýyn bolsa, zerur bolanda, heş tablisalarynda ýa-da şuňa meňzeş maglumat gurluşlarynda obýektiň takmynan ýerleşişini kesgitlemek üçin aýdalyň. obýekt gözlemegiň tizligini ýokarlandyrmak. Şertnamalara goşmaça , obýektleri deňeşdirmek bilen baglanyşykly başga bir talap bar equals. Bu, interfeýs usulynyň hashCodeyzygiderliligi . Bu talap işläp düzüjini hemişe haçan gaýdyp gelmäge borçly edýär . Twoagny, iki obýektiň logiki deňeşdirmesiniň programmanyň islendik ýerinde gapma-garşy bolmaly däldigini we hemişe yzygiderli bolmalydygyny görýäris. compareToComparableequalsx.equals(y) == truex.compareTo(y) == 0

Çeşmeler

Netijeli Java, ikinji neşir. Joşua Bloch. Gaty gowy kitabyň mugt terjimesi. Java, hünärmenleriň kitaphanasy. Tom 1. Esasy esaslar. Keý Horstmann. Biraz az teoriýa we has köp tejribe. Everythingöne hemme zat Blochyňky ýaly jikme-jik analiz edilmeýär. Şol bir deňlikde () deň pikir bar bolsa-da. Suratlardaky maglumatlar gurluşlary. HashMap Java-daky HashMap enjamynda gaty peýdaly makala. Çeşmelerine seretmegiň ýerine.
Teswirler
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION