JavaRush /Java blogi /Random-UZ /HashMap Java-da qanday ishlaydi?
gnev
Daraja

HashMap Java-da qanday ishlaydi?

Guruhda nashr etilgan
HashMap Java-da qanday ishlaydi?  - 1Ko'pincha intervyularda ular " HashMap Java'da qanday ishlaydi?" kabi savollarni berishadi. get”, “ HashMap’da usullar qanday ishlashining ichki mexanizmi nima put?”. Bu erda men oddiy misol yordamida ichki funksionallikni tushuntirishga harakat qilaman. Ortiqcha nazariyaga kirmasdan, biz misol bilan boshlaymiz, shunda siz yaxshiroq tushunishingiz va keyin usullarning Java-da getqanday ishlashini ko'rishingiz mumkin. putKeling, juda oddiy misolni olaylik. Bizda sinf (inglizcha "mamlakat") bor , biz kalit sifatida sinf ob'ektini va qiymat sifatida ushbu mamlakat poytaxti nomidan Countryfoydalanamiz . CountryQuyida kalit-qiymat juftligi xesh xaritasida qanday saqlanishini tushunishga yordam beradigan misol keltirilgan.

1. Mamlakat.java

package org.arpit.javapostsforlearning;
public class Country {

 String name;
 long population;

 public Country(String name, long population) {
  super();
  this.name = name;
  this.population = population;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public long getPopulation() {
  return population;
 }
 public void setPopulation(long population) {
  this.population = population;
 }

 // если длина имени в an objectе Country - четное число,
 // то возвращаем 31(любое случайное число), а если нечетное - 95 (любое случайное число).
 // указанный ниже метод - это не самый лучший способ генерации хеш-codeа,
 // но мы воспользуемся им для более четкого понимания хеш-карт.

 @Override
 public int hashCode() {
  if(this.name.length()%2==0)
   return 31;
  else
   return 95;
 }
 @Override
 public boolean equals(Object obj) {

  Country other = (Country) obj;
   if (name.equalsIgnoreCase((other.name)))
   return true;
  return false;
 }
}
Agar siz usullar va tengliklar haqida ko'proq tushunish va bilishni istasangiz , ushbu havolagahashcode o'tishingiz mumkin .

2. HashMapStructure.java (asosiy sinf)

import java.util.HashMap;
import java.util.Iterator;

public class HashMapStructure {

    /**
     * @author Arpit Mandliya
     */
    public static void main(String[] args) {

        Country india=new Country("India",1000);
        Country japan=new Country("Japan",10000);

        Country france=new Country("France",2000);
        Country russia=new Country("Russia",20000);

        HashMap<country,string> countryCapitalMap=new HashMap<country,string>();
        countryCapitalMap.put(india,"Delhi");
        countryCapitalMap.put(japan,"Tokyo");
        countryCapitalMap.put(france,"Paris");
        countryCapitalMap.put(russia,"Moscow");

        Iterator<country> countryCapitalIter=countryCapitalMap.keySet().iterator();//установите
        //debug-точку на этой строке(23)
        while(countryCapitalIter.hasNext())
        {
            Country countryObj=countryCapitalIter.next();
            String capital=countryCapitalMap.get(countryObj);
            System.out.println(countryObj.getName()+"----"+capital);
            }
        }
}
Endi to'xtash nuqtasini 23-qatorga qo'ying va run -> debug as-> java ilovasini ishga tushiring (tarjimonning eslatmasi - Eclipse uchun amal qiladi). Dastur 23-qatorda bajarilishini to'xtatadi, shundan so'ng countryCapitalMap-ni o'ng tugmasini bosing va tomosha qiling . Siz shunday jadvalni ko'rasiz: HashMap Java-da qanday ishlaydi?  - 2Bu erda biz quyidagilarni ko'ramiz:
  1. Entry[]nomli 16 ta hujayradan iborat massiv mavjud table;

  2. Ushbu massiv sinf ob'ektlarini saqlaydi Entry. Sinfning HashMapichki sinfi bor - Entry. Va bu sinfning misollari kalit-qiymat juftliklari. Keling, sinf tuzilishini ko'rib chiqaylik Entry:

  3. static class Entry implements Map.Entry
            {
                    final K key;
                    V value;
                    Entry next;
                    final int hash;
                    ...//продолжение codeа
            }
  4. Har safar xesh xaritasida kalit-qiymat juftligini yaratishga harakat qilganimizda, ushbu juftlik uchun sinf ob'ekti yaratiladi Entryva u yuqoridagi jadvalda saqlanadi Entry[]. Va endi siz ushbu ob'ekt aynan qaysi jadvalda (qaysi katakda) yozilishiga hayron bo'lishingiz kerak. Kalit-qiymat juftligidagi kalit uchun xesh-kod yordamida hisoblab chiqiladi hashcode(). Va bu xesh-kod jadval hujayra raqamini hisoblash uchun ishlatiladi Entry[];

  5. EntryEndi, agar siz jadvalning 10-hujayrasini ko'rsangiz, nomli sinf ob'ektini ko'rasiz HashMap$Entry;

  6. Biz 4 ta kalit-qiymat juftligini qo'shdik, lekin massivda faqat 2 tasi bor!!! Buning sababi shundaki, agar 2 ta ob'ekt bir xil xesh-kodga ega bo'lsa, ular bitta katakda saqlanadi. Lekin qanday? Ob'ektlar bog'langan ro'yxat ( ) sifatida saqlanadi LinkedList.
Bizning kalit-qiymat juftligimiz uchun xesh-kod qanday hisoblab chiqiladi.
Hashcode for Japan = 95 так How длина слова Japan имеет нечетное количество букв.
Hashcode for India = 95 так How длина слова India имеет нечетное количество букв.
HashCode for Russia = 31 так How длина слова Russia имеет четное количество букв.
HashCode for France = 31 так How длина слова France имеет четное количество букв.
Quyidagi rasm bog'langan ro'yxat g'oyasini tushuntiradi: Endi siz xesh xaritalar tuzilishi haqida allaqachon tushunchaga ega bo'lganingizdan so'ng, va usullariga HashMap Java-da qanday ishlaydi?  - 3o'tamiz . putget

Qo'ying:

Keling, ushbu usul qanday qo'llanilishini ko'rib chiqaylik:
/**
  * Метод связывает указанное meaning с указанным ключом в данной хэш-карте. Если
  * карта до этого уже содержала некоторое meaning, соответствующее этому ключу,
  * то старое meaning заменяется на указанное.
  * @param key
  *            ключ, с которым связывается указанное meaning
  * @param value
  *            meaning, связываемое с указанным ключом
  * @возвращает meaning связанное с <tt>ключом</tt>, or <tt>null</tt>,
  *         если ниHowое meaning не соответствует <tt>ключу</tt>. ( Возврат <tt>null</tt>
  *         может так же говорить о том, что в карте заведомо <tt>null</tt> был связан с
  *         <tt>ключом</tt>.)
  */
 public V put(K key, V value) {
  if (key == null)
   return putForNullKey(value);
  int hash = hash(key.hashCode());
  int i = indexFor(hash, table.length);
  for (Entry<k , V> e = table[i]; e != null; e = e.next) {
   Object k;
   if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
    V oldValue = e.value;
    e.value = value;
    e.recordAccess(this);
    return oldValue;
   }
  }

  modCount++;
  addEntry(hash, key, value, i);
  return null;
 }
Keling, ushbu kodni bosqichma-bosqich tushunishga harakat qilaylik:
  1. keyOb'ektni tenglik uchun tekshiramiz null. Agar shunday bo'lsa, u holda ob'ekt keyjoyida saqlanadi table[0], chunki uchun xesh kodi nullhar doim 0;

  2. Keyinchalik, biz ob'ekt keyusulini chaqiramiz hashcode(), bu uning xesh kodini hisoblab chiqadi. Ushbu xesh kodi sinf ob'ekti saqlanadigan qator katakchasini aniqlash uchun ishlatiladi Entry. Ba'zan shunday bo'ladiki, bu funksiya hashcodeunchalik mohirlik bilan yozilmagan, shuning uchun JDK ishlab chiquvchilari hash()argument sifatida ilgari hisoblangan xesh-kodni oladigan boshqa funktsiyani - yaratdilar. Agar siz ushbu funktsiya haqida batafsilroq o'qishga qiziqsangiz, havolaga o'tishingiz mumkin ;

  3. indexFor(hash,table.length)tablesinf ob'ekti saqlanadigan aniqlangan qatordagi ma'lum bir hujayrani aniqlash uchun ishlatiladi Entry;

  4. Bizning misolimizda ko'rganimizdek, agar ikkita ob'ekt keybir xil xesh-kodga ega bo'lsa (bu holat to'qnashuv sifatida tanilgan), u holda ular bog'langan ro'yxat shaklida saqlanadi. Shuning uchun, ushbu bosqichda biz ro'yxatimizni takrorlaymiz:

    • agar yangi hisoblangan katak bo'sh bo'lsa, sinf ob'ekti Entryto'g'ridan-to'g'ri ushbu katakchaga saqlanadi;

    • nextagar bu katak allaqachon ob'ektni o'z ichiga olgan bo'lsa, u holda maydoni ga teng bo'lgan elementga takrorlanadi null. Shundan so'ng, bizning sinf ob'ektimiz Entryro'yxatda keyingi bo'ladi;

    • Agar biz yana bir xil ob'ektni qo'shsak nima bo'ladi key? Mantiqan, u eski qiymatni almashtirishi kerak. Ha, shunday bo'ladi. equals()Takrorlash vaqtida kalitlar ( ) usuli yordamida taqqoslanadi key.equals(k). Agar natija rost bo'lsa, eski qiymat joriy ob'ektning qiymati bilan almashtiriladi Entry.

Oling:

Endi usulning qo'llanilishini ko'rib chiqamiz olish
/**
  * returns meaning, которое соответствует указанному ключу, or {@code null}, если
  * данная карта не содержит пары с указанным ключом.
  *
  *
  * <p>
  * Более точно, если в данной карте содержится такой ключ {@code k}
  * с соответствующим ему meaningм {@code v}, что {@code (key==null ? k==null : key.equals(k))},
  * то метод возвращает {@code v}; в противном случае возвращается {@code null}.
  * (может быть не более одной такой пары)
  *
  * </p><p>
  * Возвращенное meaning {@code null} не <i>обязательно</i> говорит о том, что
  * в карте нет пары с таким указанным ключом; а возможно, что в карте однозначно
  * указано соответствие этого ключа со meaningм {@code null}.
  * Можно воспользоваться операцией {@link #containsKey containsKey}, чтобы
  * отличить эти два случая
  * @see #put(Object, Object)
  */
 public V get(Object key) {
  if (key == null)
   return getForNullKey();
  int hash = hash(key.hashCode());
  for (Entry<k , V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) {
   Object k;
   if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
    return e.value;
  }
  return null;
 }
Endi siz put usulining hasshmaplarda qanday ishlashini tushunganingizdan so'ng, put usuli qanday ishlashini tushunish getjuda oddiy. Xesh xaritasidan qiymat olish usuliga biron-bir kalitni uzatganingizda:
  1. Ob'ekt Ekey tenglik uchun sinovdan o'tkaziladi null. Agar shunday bo'lsa, u holda hujayrada saqlangan ob'ektning qiymati qaytariladi table[0];

  2. Kalit ob'ektda hashcode()xesh kodini hisoblaydigan usul mavjud;

  3. indexFor(hash,table.length)tablesinf ob'ekti olinadigan muayyan massiv katakchasini aniqlash uchun ishlatiladi Entry;

  4. Massiv katak raqamini olgandan so'ng, tableu ro'yxat bo'ylab takrorlanadi va usul yordamida kalitlarni solishtiradi equals(). Agar natija rost bo'lsa, u holda ob'ektning qiymati qaytariladi Entry, aks holda - null.

Esda tutish kerak bo'lgan narsalar:

  • Sinfda kalit-qiymat juftliklarini saqlaydigan HashMapichki sinf mavjud ;Entry

  • Sinf ob'ektlari deb nomlangan Entrymassivda saqlanadi ;Entry[ ]table

  • Massiv katakchasi chelak deb ataladi va ulangan ro'yxatning birinchi elementini saqlaydi;

  • hashcode()Ob'ekt usuli keybu sinf ob'ektining paqirini topish uchun ishlatiladi Entry;

  • Agar ikkita ob'ektning kalitlari bir xil xesh-kodga ega bo'lsa, ular bir xil massiv paqirida saqlanadi table;

  • equals()Ob'ekt usuli keyuning o'ziga xosligini tasdiqlash uchun ishlatiladi;

  • Usullar equals()va hashcode()ob'ektlar valueumuman ishlatilmaydi.

Manba
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION