JavaRush /Блоги Java /Random-TG /баробар & усулҳои hashCode: амалияи истифода

баробар & усулҳои hashCode: амалияи истифода

Дар гурӯҳ нашр шудааст
Салом! Имрӯз мо дар бораи ду усули муҳим дар Java гап мезанем - equals()ва hashCode(). Ин бори аввал нест, ки мо бо онҳо вохӯрем: дар оғози курси JavaRush лексияи кӯтоҳе дар бораи он буд equals()- агар шумо онро фаромӯш карда бошед ё қаблан надида бошед, онро хонед. Усулҳои баробар & amp;  hashCode: амалияи истифода - 1Дар дарси имрӯза мо дар бораи ин мафҳумҳо ба таври муфассал сӯҳбат хоҳем кард - ба ман бовар кунед, ки дар бораи он сӯҳбат кардан лозим аст! Ва пеш аз он ки мо ба чизи нав гузарем, биёед хотираи худро дар бораи он чизе, ки аллакай фаро гирифтаем, тароват диҳем :) Тавре ки шумо дар ёд доред, муқоисаи маъмулии ду an object бо истифода аз оператори “ ==” фикри бад аст, зеро “ ==” истинодҳоро муқоиса мекунад. Ин аст мисоли мо бо мошинҳо аз лексияи ба наздикӣ:
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);
   }
}
Натиҷаи консол:

false
Чунин ба назар мерасад, ки мо ду an objectи якхелаи синфро офаридаем Car: ҳамаи майдонҳои ду мошин якхелаанд, аммо натиҷаи муқоиса ҳанӯз ҳам бардурӯғ аст. Мо аллакай сабаби онро медонем: пайвандҳо car1ва car2ишора ба суроғаҳои гуногун дар хотира, то ки онҳо баробар нестанд. Мо ҳоло ҳам мехоҳем ду an objectро муқоиса кунем, на ду истинод. Беҳтарин роҳи ҳалли муқоисаи an objectҳо ин аст equals().

усули баробар()

Шояд шумо дар хотир доред, ки мо ин усулро аз сифр эҷод намекунем, балки онро бекор мекунем - дар ниҳоят, усул equals()дар синф муайян карда шудааст Object. Аммо, дар шакли муқаррарии он каме истифода мешавад:
public boolean equals(Object obj) {
   return (this == obj);
}
Ин усул equals()дар синф муайян карда мешавад Object. Ҳамон муқоисаи пайвандҳо. Чаро ӯ чунин офарида шудааст? Хуб, созандагони забон аз куҷо медонанд, ки кадом an objectҳои барномаи шумо баробар ҳисобида мешаванд ва кадоме не? :) Ин ғояи асосии усул аст equals()- худи офаринандаи синф хусусиятҳоеро муайян мекунад, ки тавассути онҳо баробарии an objectҳои ин синф тафтиш карда мешавад. Бо ин кор, шумо методро equals()дар синфи худ бекор мекунед. Агар шумо маънои "хусусиятҳоро худатон муайян мекунед" комилан нафаҳмед, биёед як мисолро дида бароем. Дар ин чо синфи оддии одам — 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.
}
Фарз мекунем, ки мо барномае менависем, ки бояд муайян кунад, ки ду нафар дугоникҳо ҳастанд ё танҳо дугонаҳо. Мо панҷ хусусият дорем: андозаи бинӣ, ранги чашм, ороиши мӯй, мавҷудияти доғҳо ва натиҷаҳои санҷиши биологии ДНК (барои соддагӣ - дар шакли рақами code). Ба фикри шумо кадоме аз ин хусусиятҳо ба барномаи мо имкон медиҳад, ки хешовандони дугоникҳоро муайян кунанд? Усулҳои баробар & amp;  hashCode: амалияи истифода - 2Албатта, танҳо санҷиши биологӣ кафолат дода метавонад. Ду нафар метавонанд ранги чашм, ороиши мӯй, бинӣ ва ҳатто доғҳои якхела дошта бошанд - дар ҷаҳон одамони зиёде ҳастанд ва аз тасодуф канорагирӣ кардан ғайриимкон аст. Ба мо механизми боэътимод лозим аст: тандо натичаи санчиши ДНК ба мо имкон медихад, ки хулосаи дакик барорем. Ин барои усули мо чӣ маъно дорад equals()? Мо бояд онро дар синф Manбо назардошти талаботи программаамон аз нав муайян кунем. Усул бояд майдони int dnaCodeду an objectро муқоиса кунад ва агар онҳо баробар бошанд, an objectҳо баробаранд.
@Override
public boolean equals(Object o) {
   Man man = (Man) o;
   return dnaCode == man.dnaCode;
}
Оё ин дар ҳақиқат ин қадар оддӣ аст? На дарвоқеъ. Мо чизеро аз даст додем. Дар ин сурат мо барои an objectхои мо танхо як майдони «ахамиятнок»-ро муайян кардем, ки ба воситаи он баробарии онхо мукаррар карда мешавад — dnaCode. Акнун тасаввур кунед, ки мо на 1, балки 50 чунин майдони «муҳим» хоҳем дошт.Ва агар ҳамаи 50 майдони ду an object баробар бошанд, он гоҳ an objectҳо баробаранд. Ин ҳам метавонад рӯй диҳад. Проблемаи асосй дар он аст, ки хисоб кардани баробарии 50 майдон процесси вакт ва ресурсталаб аст. Акнун тасаввур кунед, ки ба ғайр аз синф, Manмо синфе дорем Woman, ки маҳз ҳамон майдонҳои дар Man. Ва агар барномасози дигар дарсҳои шуморо истифода барад, ӯ метавонад ба осонӣ дар барномаи худ чизе нависад:
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));
}
Дар ин сурат аз санчидани киматхои майдонхо фоидае нест: мо мебинем, ки мо an objectхои ду класси гуногунро дида истодаем ва онхо принципан баробар шуда наметавонанд! Ин маънои онро дорад, ки мо бояд дар метод equals()- муқоисаи an objectҳои ду синфи якхела чек гузорем. Хуб аст, ки мо дар ин бора фикр кардем!
@Override
public boolean equals(Object o) {
   if (getClass() != o.getClass()) return false;
   Man man = (Man) o;
   return dnaCode == man.dnaCode;
}
Аммо шояд мо чизи дигареро фаромӯш кардаем? Хм... Акаллан, мо бояд тафтиш кунем, ки мо an objectро бо худ мукоиса намекунем! Агар истинодҳои A ва B ба суроғаи якхела дар хотира ишора кунанд, пас онҳо як an object мебошанд ва ба мо низ лозим нест, ки барои муқоисаи 50 майдон вақтро беҳуда сарф кунем.
@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;
}
Илова бар ин, илова кардани чек барои null: ягон an object наметавонад ба , баробар бошад null, дар ин ҳолат дар чекҳои иловагӣ ягон нукта вуҷуд надорад. Бо назардошти ҳамаи ин, усули equals()синфии мо Manчунин хоҳад буд:
@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;
}
Мо ҳама санҷишҳои ибтидоии дар боло зикршударо иҷро мекунем. Агар маълум шавад, ки:
  • мо ду an objectи як синфро муқоиса мекунем
  • ин ҳамон an object нест
  • мо an objectи худро бо он мукоиса намекунемnull
...пас мо ба мукоисаи характеристикаи мухим мегузарем. Дар мо майдонхои dnaCodeду an object. Ҳангоми бекор кардани усул equals(), боварӣ ҳосил кунед, ки ин талаботҳоро риоя кунед:
  1. Рефлексия.

    Ҳар як an object бояд equals()худаш бошад.
    Мо ин талаботро аллакай ба назар гирифтем. Усули мо мегӯяд:

    if (this == o) return true;

  2. Симметрия.

    Агар a.equals(b) == true, пас b.equals(a)он бояд баргардад true.
    Усули мо низ ба ин талаб чавоб медихад.

  3. Гузариш.

    Агар ду an object ба ягон an objectи сеюм баробар бошанд, пас онҳо бояд ба ҳамдигар баробар бошанд.
    Агар a.equals(b) == trueва бошад a.equals(c) == true, чек b.equals(c)низ бояд ҳақиқиро баргардонад.

  4. Доимӣ.

    Натичаи кор equals()бояд танхо дар вакте тагьир ёбад, ки майдонхои ба он дохилшуда тагьир ёбанд. Агар маълумоти ду an object тагйир наёфта бошад, натичахои тафтиш equals()бояд хамеша якхела бошанд.

  5. Нобаробарӣ бо null.

    Барои ҳар як an object, чек a.equals(null)бояд бардурӯғ баргардонад.Ин
    на танҳо маҷмӯи баъзе "тавсияҳои муфид", балки шартномаи қатъии усулҳоест , ки дар ҳуҷҷатҳои Oracle муқаррар шудааст.

усули hashCode().

Акнун биёед дар бораи усул гап занем hashCode(). Чаро он лозим аст? Махз бо хамин максад — мукоиса кардани an objectхо. Аммо мо онро аллакай дорем equals()! Чаро усули дигар? Ҷавоб оддӣ аст: баланд бардоштани ҳосилнокӣ. Функсияи хэш, ки бо усули , дар Java муаррифӣ мешавад hashCode(), барои ҳама гуна an object арзиши ададии собитро бармегардонад. Дар мавриди Java, усул hashCode()рақами 32-битии навъи int. Муқоисаи ду ададро бо ҳамдигар нисбат ба муқоисаи ду an object бо усули метод хеле тезтар аст equals(), хусусан агар он майдонҳои зиёдеро истифода барад. Агар барномаи мо an objectҳоро муқоиса кунад, ин корро бо codeи hash иҷро кардан хеле осонтар аст ва танҳо агар онҳо баробар бошанд hashCode()- ба муқоиса бо equals(). Дар омади гап, ин аст, ки чӣ гуна сохторҳои маълумот ба хэш асосёфта кор мекунанд - масалан, сохторе, ки шумо медонед HashMap! Усули hashCode()монанди equals(), аз ҷониби худи таҳиякунанда бекор карда мешавад. Ва ба монанди барои equals(), усул hashCode()дорои талаботи расмии дар ҳуҷҷатҳои Oracle зикршуда:
  1. Агар ду an object баробар бошанд (яъне, усул equals()ҳақиқиро бармегардонад), онҳо бояд як рамзи хэш дошта бошанд.

    Дар акси ҳол усулҳои мо бемаънӣ хоҳанд буд. Санҷиши hashCode(), тавре ки мо гуфтем, бояд аввал барои беҳтар кардани фаъолият бошад. Агар рамзҳои хэш гуногун бошанд, чек бардурӯғ бармегардад, гарчанде ки an objectҳо воқеан баробаранд (чунон ки мо дар метод муайян кардем equals()).

  2. Агар усул hashCode()дар як an object якчанд маротиба даъват карда шавад, он бояд ҳар дафъа ҳамон рақамро баргардонад.

  3. Қоидаи 1 баръакс кор намекунад. Ду an objectи гуногун метавонанд як рамзи хэш дошта бошанд.

Қоидаи сеюм каме печида аст. Ин чӣ гуна буда метавонад? Шарҳ хеле оддӣ аст. Усул hashCode()бармегардад int. intрақами 32-бит аст. Он дорои шумораи маҳдуди арзишҳо - аз -2,147,483,648 то +2,147,483,647. Ба ибораи дигар, каме бештар аз 4 миллиард варианти рақам вуҷуд дорад int. Акнун тасаввур кунед, ки шумо барномаеро барои нигоҳ доштани маълумот дар бораи тамоми одамони зинда дар рӯи замин эҷод мекунед. Ҳар як шахс дорои an objectи синфии худро хоҳад дошт Man. ~7,5 миллиард нафар дар рӯи замин зиндагӣ мекунанд. Ба ибораи дигар, новобаста аз он ки Manмо алгоритми хубе барои табдил додани an objectҳо ба рақамҳо менависем, мо танҳо рақамҳои кофӣ нахоҳем дошт. Мо танҳо 4,5 миллиард вариант дорем ва шумораи зиёди одамон. Ин маънои онро дорад, ки новобаста аз он ки мо чӣ қадар кӯшиш мекунем, рамзҳои хэш барои баъзе одамони гуногун якхела хоҳанд буд. Ин вазъият (рамзҳои хэш-и ду an objectи гуногун мувофиқ) бархӯрд номида мешавад. Яке аз ҳадафҳои барномасоз ҳангоми барҳам додани усул hashCode()то ҳадди имкон кам кардани шумораи эҳтимолии бархӯрдҳо мебошад. Усули мо hashCode()барои синф Manбо назардошти ҳамаи ин қоидаҳо чӣ гуна хоҳад буд? Монанди ин:
@Override
public int hashCode() {
   return dnaCode;
}
Ҳайрон? :) Ногаҳон, аммо агар шумо ба талабот нигаред, мебинед, ки мо ҳама чизро риоя мекунем. Объектҳое, ки an objectҳои мо equals()ҳақиқиро бармегардонанд, дар hashCode(). Агар ду an objectи мо Manдар арзиш баробар бошанд equals(яъне арзиши якхела доранд dnaCode), усули мо ҳамон рақамро бармегардонад. Биёед мисоли мураккабтарро дида бароем. Фарз мекунем, ки барномаи мо бояд барои муштариёни коллектор мошинҳои боҳашамат интихоб кунад. Ҷамъоварӣ як чизи мураккаб аст ва хусусиятҳои зиёде дорад. Мошини соли 1963 назар ба хамин машинаи соли 1964-ум 100 баробар кимат шуда метавонад. Мошини сурхи соли 1970 метавонад назар ба мошини кабуди ҳамон сол 100 маротиба гаронтар бошад. Усулҳои баробар & amp;  hashCode: амалияи истифода - 4Дар ҳолати аввал, бо синф Man, мо аксари майдонҳоро (яъне, хусусиятҳои шахс) ҳамчун ночиз хориҷ кардем ва танҳо майдонро барои муқоиса истифода бурдем dnaCode. Дар ин ҷо мо бо як минтақаи хеле нодир кор карда истодаем ва дар он ҷо тафсилоти хурд вуҷуд надорад! Ин аст синфи мо 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.
}
Дар ин чо хангоми мукоиса кардан мо бояд хамаи майдонхоро ба назар гирем. Ҳар як хато метавонад барои муштарӣ садҳо ҳазор доллар арзиш дошта бошад, аз ин рӯ бехатар будан беҳтар аст:
@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);
}
Мо дар усули худ equals()хамаи чекхоеро, ки пештар дар бораи он сухан ронда будем, фаромуш намекардем. Аммо акнун мо хар як се майдони an objectхои худро мукоиса мекунем. Дар ин барнома баробарӣ бояд дар ҳама соҳа мутлақ бошад. Дар бораи чӣ hashCode?
@Override
public int hashCode() {
   int result = model == null ? 0 : model.hashCode();
   result = result + manufactureYear;
   result = result + dollarPrice;
   return result;
}
Майдон modelдар синфи мо сатр аст. Ин қулай аст: Stringусул hashCode()аллакай дар синф бекор карда шудааст. Мо codeи хэш-и майдонро ҳисоб мекунем modelва ба он маблағи ду майдони рақамии дигарро илова мекунем. Дар Java як ҳиллаест, ки барои кам кардани шумораи бархӯрдҳо истифода мешавад: ҳангоми ҳисоб кардани codeи ҳаш, натиҷаи мобайниро ба рақами тоқи аслӣ зарб кунед. Рақами маъмултарин 29 ё 31 аст. Мо ҳоло ба тафсилоти математика намеравем, аммо барои истинод дар оянда, дар хотир доред, ки зарб задани натиҷаҳои мобайнӣ ба рақами кофӣ тоқ, ба “паҳн кардани” натиҷаҳои ҳаш кӯмак мекунад. функсия ва ба an objectҳои камтар бо ҳамон hashcode хотима меёбад. Барои усули мо hashCode()дар LuxuryAuto он чунин хоҳад буд:
@Override
public int hashCode() {
   int result = model == null ? 0 : model.hashCode();
   result = 31 * result + manufactureYear;
   result = 31 * result + dollarPrice;
   return result;
}
Шумо метавонед бештар дар бораи тамоми нозукиҳои ин механизм дар ин мақола дар StackOverflow ва инчунин дар китоби Ҷошуа Блок " Effective Java " хонед. Ниҳоят, боз як нуктаи муҳимеро зикр кардан лозим аст. Ҳар дафъа ҳангоми барҳам додани equals(), hashCode()мо майдонҳои муайяни an objectро интихоб мекардем, ки дар ин усулҳо ба назар гирифта мешуданд. Аммо оё мо метавонем соҳаҳои гуногунро дар equals()ва hashCode()? Аз ҷиҳати техникӣ, мо метавонем. Аммо ин як фикри бад аст ва ин аст, ки чаро:
@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;
}
Инҳоянд усулҳои мо equals()барои hashCode()синфи LuxuryAuto. Усул hashCode()бетағйир монд ва equals()мо майдонро аз метод хориҷ кардем model. Ҳоло модел барои муқоисаи ду an object аз рӯи equals(). Аммо он ҳанӯз ҳам ҳангоми ҳисоб кардани codeи hash ба назар гирифта мешавад. Дар натиҷа мо чӣ ба даст меорем? Биёед ду мошин эҷод кунем ва онро тафтиш кунем!
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
Хатогӣ! Бо истифода аз майдонхои гуногун барои equals()ва hashCode()мо шартномаи барои онхо мукарраршударо вайрон кардем! Ду equals()an objectи баробар бояд рамзи хэш-и якхела дошта бошанд. Мо барои онҳо маъноҳои гуногун дорем. Чунин хатогиҳо метавонанд ба оқибатҳои аҷибтарин оварда расонанд, хусусан ҳангоми кор бо коллексияҳое, ки ҳаэшро истифода мебаранд. Аз ин рӯ, ҳангоми аз нав муайян кардан equals()ва hashCode()истифодаи ҳамон майдонҳо дуруст хоҳад буд. Лексия хеле тӯлонӣ буд, аммо имрӯз шумо бисёр чизҳои навро омӯхтед! :) Вақти он расидааст, ки ба ҳалли мушкилот баргардем!
Шарҳҳо
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION