JavaRush /Блоги Java /Random-TG /Шартномаҳои баробар ва hashCode ё ҳар чизе ки он аст
Aleksandr Zimin
Сатҳи
Санкт-Петербург

Шартномаҳои баробар ва hashCode ё ҳар чизе ки он аст

Дар гурӯҳ нашр шудааст
Аксарияти кулли барномасозони Java, албатта, медонанд, ки усулҳо бо ҳамдигар зич equalsалоқаманданд hashCodeва тавсия дода мешавад, ки ҳардуи ин усулҳоро дар синфҳои худ пайваста барҳам диҳед. Шумораи каме камтар медонад, ки чаро ин тавр аст ва агар ин қоида вайрон карда шавад, чӣ оқибатҳои ғамангез ба амал меоянд. Ман пешниҳод мекунам, ки мафҳуми ин усулҳоро баррасӣ карда, ҳадафи онҳоро такрор кунед ва фаҳмед, ки чаро онҳо ин қадар пайвастанд. Ман ин мақоларо ба мисли мақолаи қаблӣ дар бораи боркунии синфҳо барои худ навиштам, то дар ниҳоят тамоми ҷузъиёти масъаларо ошкор кунам ва дигар ба манбаъҳои тарафи сеюм барнагардам. Бинобар ин ман аз танкиди конструктивй шод хохам шуд, зеро агар дар ягон чо камбудихо мавчуд бошанд, бояд бартараф карда шаванд. Мақола, мутаассифона, хеле дароз шуд.

ба қоидаҳои бекоркунӣ баробар аст

Усули equals()дар Java барои тасдиқ ё рад кардани далели мантиқӣ баробар будани ду an objectи пайдоиши якхела лозим аст . Яъне, ҳангоми муқоисаи ду an object, барномасоз бояд фаҳмад, ки майдонҳои муҳими онҳо баробаранд . Зарур нест, ки ҳамаи майдонҳо бояд якхела бошанд, зеро усул баробарии мантиқироequals() дар назар дорад . Аммо баъзан барои истифодаи ин усул зарурати махсус вуҷуд надорад. Тавре ки мегӯянд, роҳи осонтарини пешгирӣ кардани мушкилот бо истифодаи механизми мушаххас ин истифода набурдани он аст. Инчунин бояд қайд кард, ки вақте ки шумо шартномаро вайрон мекунед, шумо назоратро дарк мекунед, ки чӣ гуна an objectҳо ва сохторҳои дигар бо an objectи шумо ҳамкорӣ мекунанд. Ва баъдан пайдо кардани сабаби хатогӣ хеле душвор хоҳад буд. equals

Вақте ки ин усулро аз байн набаред

  • Вақте ки ҳар як мисоли синф беназир аст.
  • Ба андозаи бештар, ин ба он синфҳое дахл дорад, ки рафтори мушаххасро таъмин мекунанд, на барои кор бо маълумот. Масалан, ба монанди синф Thread. Барои онҳо equals, татбиқи усули пешниҳодкардаи синф Objectбеш аз кофист. Мисоли дигар синфҳои enum ( Enum).
  • Ҳангоме ки дар асл аз синф талаб карда намешавад, ки эквивалентии мисолҳои онро муайян кунад.
  • Масалан, барои синф java.util.Randomбарои муқоисаи мисолҳои синф бо ҳамдигар, муайян кардани он, ки оё онҳо метавонанд як пайдарпаии рақамҳои тасодуфиро баргардонанд, умуман лозим нест. Танҳо аз сабаби он ки табиати ин синф ҳатто чунин рафторро дар назар надорад.
  • Вақте ки синфе, ки шумо васеъ мекунед, аллакай татбиқи усули худро дорад equalsва рафтори ин татбиқ ба шумо мувофиқ аст.
  • Масалан, барои синфҳои Set, List, Mapтатбиқ equalsдар AbstractSet, AbstractListва AbstractMapмувофиқ аст.
  • Ва дар ниҳоят, ҳеҷ зарурате нест, equalsки кай доираи синфи шумост privateё аст package-privateва шумо боварӣ доред, ки ин усул ҳеҷ гоҳ даъват карда намешавад.

шартнома баробар аст

Ҳангоми бекор кардани усул, equalsтаҳиякунанда бояд қоидаҳои асосии дар мушаххасоти забони Java муайяншударо риоя кунад.
  • Рефлексия
  • барои ҳар як арзиши додашуда x, ифода x.equals(x)бояд баргардад true.
    Дода - чунин маъно дорадx != null
  • Симметрия
  • барои ҳама арзишҳои додашуда xва y, x.equals(y)бояд trueтанҳо дар сурати y.equals(x)баргардонидани он баргардад true.
  • Гузариш
  • барои ҳар як арзишҳои додашуда ва xагар yбаргардад zва баргардад , бояд арзишро баргардонад . x.equals(y)truey.equals(z)truex.equals(z)true
  • Мутобиқати
  • барои ҳар як арзишҳои додашуда xва yзанги такрорӣ x.equals(y)арзиши занги қаблиро ба ин усул бармегардонад, ба шарте ки майдонҳои барои муқоисаи ду an object истифодашуда дар байни зангҳо тағир наёбанд.
  • Муқоиса null
  • барои ҳар як арзиши додашуда xзанг x.equals(null)бояд баргардад false.

ба вайрон кардани шартнома баробар аст

Бисёр синфҳо, ба монанди синфҳои Java Collections Framework, аз татбиқи метод вобастаанд equals(), бинобар ин шумо набояд онро сарфи назар кунед, зеро Вайрон кардани шартномаи ин усул метавонад боиси беақлона кор кардани ариза гардад ва дар ин ҳолат пайдо кардани сабаб хеле душвор хоҳад буд. Тибқи принсипи рефлексивӣ , ҳар як an object бояд ба худ баробар бошад. Агар ин принсип вайрон карда шавад, вақте ки мо an objectро ба коллексия илова мекунем ва сипас онро бо истифода аз усул ҷустуҷӯ мекунем, contains()мо an objectеро, ки нав ба коллексия илова кардем, ёфта наметавонем. Шарти симметрия изҳор мекунад, ки ҳар ду an object новобаста аз тартиби муқоисаи онҳо бояд баробар бошанд. equalsМасалан, агар шумо синфе дошта бошед, ки танҳо як майдони навъи сатр дошта бошад, муқоисаи ин майдон бо сатри усул нодуруст хоҳад буд . Зеро дар сурати муқоисаи баръакс, усул ҳамеша арзиши 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);
}
Аз шарти гузариш чунин бармеояд, ки агар яке аз се an object баробар бошад, дар ин маврид хар се бояд баробар бошанд. Ин принсипро ба осонӣ вайрон кардан мумкин аст, вақте ки зарурати васеъ кардани синфи муайяни базавӣ тавассути илова кардани ҷузъи муҳим ба он . Масалан, ба синф Pointбо координатҳо xва yшумо бояд ранги нуқтаро бо васеъ кардани он илова кунед. Барои ин ба шумо лозим меояд, ки синферо ColorPointбо майдони мувофиқ эълон кунед color. Ҳамин тариқ, агар дар синфи васеъшуда мо equalsусули волидайнро меномем ва дар волидайн мо тахмин кунем, ки танҳо координатҳо xва муқоиса карда мешаванд y, пас ду нуқтаи рангҳои гуногун, вале координатаҳои якхела баробар ҳисобида мешаванд, ки ин нодуруст аст. Дар ин ҳолат ба синфи ҳосилшуда барои фарқ кардани рангҳо ёд додан лозим аст. Барои ин, шумо метавонед ду усулро истифода баред. Аммо яке қоидаи симметрияро вайрон мекунад ва дуюм - транзитивӣ .

// Первый способ, нарушая симметричность
// Метод переопределен в классе ColorPoint
@Override
public boolean equals(Object o) {
    if (!(o instanceof ColorPoint)) return false;
    return super.equals(o) && ((ColorPoint) o).color == color;
}
Дар ин ҳолат, занг point.equals(colorPoint)арзиши true, ва муқоиса colorPoint.equals(point)бармегардад false, зеро an objectи синфи «он»-ро интизор аст. Хамин тавр, коидаи симметрия вайрон карда мешавад. Усули дуюм гузаронидани санҷиши "кӯр" -ро дар бар мегирад, агар дар бораи ранги нуқта маълумот мавҷуд набошад, яъне мо синф дорем Point. Ё рангро тафтиш кунед, агар маълумот дар бораи он мавҷуд бошад, яъне an objectи синфро муқоиса кунед 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;
}
Дар ин чо принципи гузариш ба таври зерин вайрон карда мешавад. Фарз мекунем, ки таърифи an objectҳои зерин вуҷуд дорад:

ColorPoint p1 = new ColorPoint(1, 2, Color.RED);
Point p2 = new Point(1, 2);
ColorPoint p3 = new ColorPoint(1, 2, Color.BLUE);
Ҳамин тариқ, гарчанде ки баробарӣ p1.equals(p2)ва қаноатманд аст p2.equals(p3), p1.equals(p3)он арзишро бармегардонад false. Дар баробари ин, усули дуюм, ба назари ман, камтар ҷолиб менамояд, зеро Дар баъзе мавридҳо, алгоритм метавонад нобино бошад ва муқоисаро пурра иҷро накунад ва шумо дар ин бора хабар надоред. Каме шеър Умуман, чунон ки ман мефахмам, халли конкретии ин масъала нест. Як андешаи як муаллифи бонуфуз бо номи Кей Хорстман вуҷуд дорад, ки шумо метавонед истифодаи операторро instanceofбо занги методе иваз кунед getClass(), ки синфи an objectро бармегардонад ва пеш аз оғози муқоисаи худи an objectҳо, боварӣ ҳосил кунед, ки онҳо як навъанд. , ва ба факти умумии пайдоиши онхо эътибор намедиханд. Ҳамин тариқ, қоидаҳои симметрия ва транзитивӣ қонеъ карда мешаванд. Аммо дар айни замон, дар тарафи дигари баррикада як муаллифи дигар, ки дар доираҳои васеъ эҳтиром надорад, Ҷошуа Блох меистад, ки бар ин назар аст, ки ин бархӯрд принсипи ивазкунии Барбара Лисковро вайрон мекунад. Ин принсип мегӯяд, ки "codeи занг бояд ба синфи асосӣ ҳамон тавре ки зерсинфҳои он бидуни донистани он муносибат кунад . " Ва дар халли пешниходкардаи Хорстман ин принцип ба таври равшан вайрон карда мешавад, зеро ин ба татбики он вобаста аст. Хулоса, маълум аст, ки масъала торик аст. Инчунин бояд қайд кард, ки Хорстманн қоидаи татбиқи равиши худро равшан мекунад ва бо забони оддии англисӣ менависад, ки шумо бояд ҳангоми таҳияи дарсҳо дар бораи стратегия қарор қабул кунед ва агар санҷиши баробарӣ танҳо аз ҷониби суперкласс гузаронида шавад, шумо метавонед ин корро тавассути иҷрои амалиёт instanceof. Дар акси ҳол, вақте ки семантикаи чек вобаста ба синфи ҳосилшуда тағир меёбад ва татбиқи усул бояд ба зинанизоми поён кӯчонида шавад, шумо бояд усули getClass(). Ҷошуа Блоч, дар навбати худ, пешниҳод мекунад, ки меросро тарк кунанд ва таркиби an objectро тавассути дохил кардани ColorPointсинф ба синф Pointва пешниҳоди усули дастрасӣ asPoint()барои ба даст овардани маълумот дар бораи нуқта истифода баранд. Ин аз вайрон кардани ҳама қоидаҳо пешгирӣ мекунад, аммо, ба андешаи ман, фаҳмидани codeро душвортар мекунад. Варианти сеюм ин истифодаи тавлиди автоматии усули баробар бо истифода аз IDE мебошад. Дар омади гап, идея насли Horstmann-ро таҷдид мекунад, ки ба шумо имкон медиҳад стратегияи татбиқи усулро дар суперкласс ё наслҳои он интихоб кунед. Ниҳоят, қоидаи мувофиқати навбатӣ мегӯяд, ки ҳатто агар an objectҳо тағир xнаёбанд y, дубора даъват кардани онҳо x.equals(y)бояд ҳамон арзиши қаблиро баргардонад. Қоидаи ниҳоӣ ин аст, ки ҳеҷ як an object набояд ба null. Дар ин ҷо ҳама чиз равшан аст null- ин номуайянӣ аст, оё an object ба номуайянӣ баробар аст? Маълум нест, яъне false.

Алгоритми умумӣ барои муайян кардани баробарҳо

  1. Санҷед, ки баробарии истинодҳои an objectҳо thisва параметрҳои метод o.
    if (this == o) return true;
  2. Санҷед, ки оё пайванд муайян шудааст o, яъне оё он аст null.
    Агар дар оянда ҳангоми муқоисаи намудҳои an objectҳо оператор истифода шавад instanceof, ин ҷузъро партофтан мумкин аст, зеро ин параметр falseдар ин ҳолат бармегардад null instanceof Object.
  3. Навъҳои an objectро thisбо истифода аз oоператор instanceofё усул getClass(), ки аз рӯи тавсифи дар боло овардашуда ва интуитсияи шахсии худ роҳнамоӣ мекунанд, муқоиса кунед.
  4. Агар усул equalsдар зерсинф бекор карда шуда бошад, ҳатман занг занедsuper.equals(o)
  5. Навъи параметрро oба синфи зарурӣ табдил диҳед.
  6. Муқоисаи ҳамаи майдонҳои an objectи муҳимро иҷро кунед:
    • барои намудҳои ибтидоӣ (ба истиснои floatва double), бо истифода аз оператор==
    • барои майдонҳои истинод шумо бояд усули онҳоро даъват кунедequals
    • барои массивҳо, шумо метавонед итератсияи даврӣ ё усулро истифода баредArrays.equals()
    • барои намудхо floatва doubleистифода бурдани усулхои мукоисаи синфхои муво-фики парпеч Float.compare()ваDouble.compare()
  7. Ва ниҳоят, ба се савол ҷавоб диҳед: оё усули татбиқшуда симметрӣ аст ? гузаранда ? розй шудед ? Ду принсипи дигар ( рефлексивӣ ва итминон ) одатан ба таври худкор иҷро карда мешаванд.

Қоидаҳои бекоркунии HashCode

Хэш рақамест, ки аз an object тавлид шудааст, ки ҳолати онро дар ягон лаҳза тавсиф мекунад. Ин рақам дар Java асосан дар ҷадвалҳои ҳаш ба монанди HashMap. Дар ин ҳолат, функсияи хэшии ба даст овардани адад дар асоси an object бояд тавре амалӣ карда шавад, ки тақсимоти нисбатан баробари элементҳо дар саросари ҷадвали hash таъмин карда шавад. Ва инчунин барои кам кардани эҳтимолияти бархӯрд, вақте ки функсия як арзишро барои калидҳои гуногун бармегардонад.

hashCode шартнома

Барои амалисозии функсияи hash, мушаххасоти забон қоидаҳои зеринро муайян мекунад:
  • як ё якчанд маротиба даъват кардани усул hashCodeдар ҳамон an object бояд ҳамон арзиши хэшро баргардонад, ба шарте ки майдонҳои an object дар ҳисобкунии арзиш тағир наёфта бошанд.
  • даъват кардани усул hashCodeдар ду an object бояд ҳамеша як рақамро баргардонад, агар an objectҳо баробар бошанд (даъват кардани усул equalsдар ин an objectҳо бармегардад true).
  • даъват кардани усул hashCodeдар ду an objectи нобаробар бояд арзишҳои гуногуни hash баргардонад. Гарчанде ки ин талабот ҳатмӣ нест, бояд ба назар гирифт, ки татбиқи он ба иҷрои ҷадвалҳои ҳаш таъсири мусбат мерасонад.

Усулҳои баробар ва hashCode бояд якҷоя бекор карда шаванд

Бар асоси шартномаҳои дар боло тавсифшуда, аз ин бармеояд, ки ҳангоми бекор кардани усул дар codeи худ equals, шумо бояд ҳамеша методро бекор кунед hashCode. Азбаски воқеан ду мисоли синф аз он сабаб фарқ мекунанд, ки онҳо дар минтақаҳои гуногуни хотира ҷойгиранд, онҳо бояд мувофиқи баъзе меъёрҳои мантиқӣ муқоиса карда шаванд. Мутаносибан, ду an objectи аз ҷиҳати мантиқӣ баробар бояд арзиши якхелаи хешро баргардонанд. Агар танҳо яке аз ин усулҳо бекор карда шавад, чӣ мешавад?
  1. equalsҲа hashCodeНе

    Фарз мекунем, ки мо методро equalsдар синфи худ дуруст муайян кардем ва hashCodeқарор додем, ки усулро ҳамон тавре ки дар синф аст, тарк кунем Object. Он гоҳ аз нуқтаи назари усул equalsду an object аз ҷиҳати мантиқӣ баробар хоҳанд буд, дар ҳоле ки аз нуқтаи назари усул hashCodeонҳо ҳеҷ чизи умумӣ надоранд. Ва ҳамин тавр, бо ҷойгир кардани an object дар ҷадвали ҳаш, мо хатари онро ба даст наовардани онро бо калид дорем.
    Масалан, ба ин монанд:

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

    Аён аст, ки an objectи ҷойгиршуда ва an objectи ҷустуҷӯшаванда ду an objectи гуногун мебошанд, гарчанде ки онҳо аз ҷиҳати мантиқӣ баробаранд. Аммо, зеро онҳо арзишҳои гуногуни хэш доранд, зеро мо шартномаро вайрон кардем, мо гуфта метавонем, ки мо an objectи худро дар ҷое дар дохor ҷадвали ҳаш гум кардем.

  2. hashCodeҲа equalsНе.

    Чӣ мешавад, агар мо усулро бекор кунем hashCodeва equalsтатбиқи усулро аз синф мерос гирем Object. Тавре ки шумо медонед, equalsусули пешфарз танҳо нишондиҳандаҳоро бо an objectҳо муқоиса карда, муайян мекунад, ки оё онҳо ба як an object ишора мекунанд. Фарз мекунем, ки hashCodeмо усулро мувофиқи ҳама қонунҳо навиштаем, яъне онро бо истифода аз IDE тавлид кардем ва он ҳамон арзишҳои хэшро барои an objectҳои мантиқии якхела бармегардонад. Аён аст, ки бо ин кор мо аллакай ягон механизми мукоисаи ду an objectро муайян кардем.

    Аз ин рӯ, мисоли параграфи қаблӣ бояд аз ҷиҳати назариявӣ иҷро карда шавад. Аммо мо то ҳол an objectи худро дар ҷадвали ҳаш ёфта наметавонем. Гарчанде ки мо ба ин наздик хоҳем буд, зеро ҳадди аққал мо як сабади мизи ҳашро пайдо хоҳем кард, ки дар он an object хобида хоҳад буд.

    Барои бомуваффақият ҷустуҷӯ кардани an object дар ҷадвали hash, ба ғайр аз муқоисаи қимматҳои хеши калид, муайян кардани баробарии мантиқии калид бо an objectи ҷустуҷӯшуда низ истифода мешавад. Ин аст, ки equalsбидуни аз эътибор соқит кардани усул ҳеҷ роҳе нест.

Алгоритми умумӣ барои муайян кардани hashCode

Дар ин ҷо, ба назарам, шумо набояд аз ҳад зиёд хавотир шавед ва усулро дар IDE дӯстдоштаи худ эҷод кунед. Азбаски ҳамаи ин тағирёбии битҳо ба рост ва чап дар ҷустуҷӯи таносуби тиллоӣ, яъне тақсимоти муқаррарӣ - ин барои дугонаҳои комилан якрав аст. Шахсан ман шубҳа дорам, ки ман метавонам беҳтар ва зудтар аз ҳамон Идея кор кунам.

Ба ҷои хулоса

Ҳамин тариқ, мо мебинем, ки усулҳо дар забони Java нақши дақиқ equalsдоранд ва барои ба даст овардани баробарии мантиқии ду an object тарҳрезӣ шудаанд. hashCodeДар мавриди усул, equalsин ба муқоисаи an objectҳо робитаи мустақим дорад, дар сурати hashCodeғайримустақим, вақте ки лозим аст, бигӯем, ки ҷойгиршавии тақрибии an objectро дар ҷадвалҳои ҳеш ё сохторҳои шабеҳи додаҳо муайян кунед, то суръати чустучуи an objectро баланд бардоранд. Ба гайр аз шартномахо боз як талаби марбут ба мукоисаи an objectхо мавчуд аст equals. hashCodeИн мувофиқати усули compareToинтерфейс Comparableбо equals. Ин талабот таҳиякунандаро вазифадор мекунад, ки ҳамеша x.equals(y) == trueҳангоми x.compareTo(y) == 0. Яъне мо мебинем, ки муќоисаи мантиќии ду an object набояд дар њељ љои замима мухолиф бошад ва њамеша пайваста бошад.

Сарчашмаҳо

Java самаранок, Нашри дуюм. Ҷошуа Блок. Тарҷумаи ройгони китоби хеле хуб. Java, китобхонаи касбӣ. Ҷилди 1. Асосҳо. Кей Хорстман. Каме камтар назария ва амалияи бештар. Аммо ҳама чиз мисли Блок ба таври муфассал таҳлил карда нашудааст. Ҳарчанд аст, назари оид ба ҳамон баробар нест (). Сохторҳои маълумот дар тасвирҳо. HashMap Мақолаи бениҳоят муфид дар дастгоҳи HashMap дар Java. Ба ҷои ҷустуҷӯи манбаъҳо.
Шарҳҳо
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION