JavaRush /Java Blogu /Random-AZ /HashMap Java-da necə işləyir?
gnev
Səviyyə

HashMap Java-da necə işləyir?

Qrupda dərc edilmişdir
HashMap Java-da necə işləyir?  - 1Çox vaxt müsahibələrdə insanlar “ HashMap Java-da necə işləyir?” kimi suallar verirlər. get”, “Metodların HashMap -da işləməsinin daxili mexanizmi nədir put?”. Burada sadə bir nümunə ilə daxili funksionallığı izah etməyə çalışacağam. Çox nəzəriyyəyə girmədən, bir nümunə ilə başlayacağıq ki, siz daha yaxşı başa düşəsiniz və sonra metodların Java-da getnecə işlədiyini görə biləsiniz. putÇox sadə bir misal götürək. Bizim sinifimiz var (ingiliscə “ölkə”), açar kimi sinif obyektini, dəyər kimi isə bu ölkənin paytaxtının adını Countryistifadə edəcəyik . CountryAşağıda açar-dəyər cütünün hash xəritəsində necə saxlanacağını anlamağa kömək etmək üçün bir nümunə verilmişdir.

1. Ölkə.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;
 }
}
Metodlar və bərabərliklər haqqında daha çox başa düşmək və öyrənmək istəyirsinizsə , bu linkihashcode izləyə bilərsiniz .

2. HashMapStructure.java(əsas sinif)

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);
            }
        }
}
İndi kəsilmə nöqtəsini 23-cü sətirə təyin edin və run -> debug as-> java proqramını işə salın (tərcüməçinin qeydi - Eclipse üçün etibarlıdır). Proqram 23-cü sətirdə icranı dayandıracaq, bundan sonra countryCapitalMap üzərinə sağ klikləyin və watch seçin . Siz belə bir cədvəl görəcəksiniz: HashMap Java-da necə işləyir?  - 2Burada aşağıdakıları görürük:
  1. Entry[]adlı 16 xanadan ibarət massiv var table;

  2. Bu massiv sinif obyektlərini saxlayır Entry. Sinfin HashMapdaxili sinfi var - Entry. Və bu sinfin nümunələri açar-dəyər cütləridir. Sinif quruluşuna nəzər salaq Entry:

  3. static class Entry implements Map.Entry
            {
                    final K key;
                    V value;
                    Entry next;
                    final int hash;
                    ...//продолжение codeа
            }
  4. Hər dəfə hash xəritəsində açar-dəyər cütlüyü yaratmağa çalışdığımız zaman həmin cütlük üçün sinif obyekti yaradılacaq Entryvə o, yuxarıdakı cədvəldə saxlanılacaq Entry[]. İndi isə bu obyektin məhz bu cədvəldə harada (hansı xanada) yazılacağı ilə maraqlanmalısınız. Açar-dəyər cütlüyündəki açar üçün hash kodu istifadə edərək hesablanır hashcode(). Və bu hash kodu masanın hüceyrə nömrəsini hesablamaq üçün istifadə olunur Entry[];

  5. Entryİndi cədvəlin 10-cu xanasına baxsanız, adlı bir sinif obyekti görəcəksiniz HashMap$Entry;

  6. Biz 4 açar-dəyər cütü əlavə etdik, lakin massivdə yalnız 2 var!!! Bunun səbəbi, əgər 2 obyektin eyni hash kodu varsa, o zaman onlar eyni xanada saxlanılacaq. Bəs necə? Obyektlər əlaqəli siyahı ( ) kimi saxlanılacaq LinkedList.
Açar-dəyər cütlərimiz üçün hash kodunun necə hesablanacağı budur.
Hashcode for Japan = 95 так How длина слова Japan имеет нечетное количество букв.
Hashcode for India = 95 так How длина слова India имеет нечетное количество букв.
HashCode for Russia = 31 так How длина слова Russia имеет четное количество букв.
HashCode for France = 31 так How длина слова France имеет четное количество букв.
Aşağıdakı rəqəm əlaqəli siyahı ideyasını izah edəcək: İndi artıq hash xəritələrinin strukturu haqqında anlayışınız olduğundan, və HashMap Java-da necə işləyir?  - 3üsullarına keçək . putget

Qoy:

Bu metodun necə istifadə edildiyinə baxaq:
/**
  * Метод связывает указанное 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;
 }
İndi bu kodu addım-addım anlamağa çalışaq:
  1. keyObyektin bərabərliyini yoxlayırıq null. Əgər belədirsə, o zaman obyekt keyyerdə saxlanacaq, table[0]çünki hash kodu nullhəmişə 0-dır;

  2. Sonra, biz onun hash kodunu hesablayacaq obyektin keymetodunu çağırırıq. hashcode()Bu hash kodu sinif obyektinin saxlanacağı massiv xanasını müəyyən etmək üçün istifadə olunur Entry. Bəzən elə olur ki, bu funksiya hashcodeçox məharətlə yazılmır, ona görə də JDK tərtibatçıları hash()əvvəllər hesablanmış hash kodunu arqument kimi götürən fərqli funksiya - yaradıblar. Bu funksiya haqqında daha ətraflı oxumaq istəyirsinizsə, linki izləyə bilərsiniz ;

  3. indexFor(hash,table.length)tablesinif obyektinin saxlanması üçün müəyyən ediləcəyi massivdə xüsusi xananı təyin etmək üçün istifadə olunur Entry;

  4. Nümunəmizdə gördüyümüz kimi, əgər iki obyekt keyeyni hash koduna malikdirsə (bu vəziyyət toqquşma kimi tanınır), onda onlar əlaqəli siyahı şəklində saxlanacaqlar. Buna görə də, bu mərhələdə siyahımızı təkrarlayırıq:

    • yeni hesablanmış xana boşdursa, sinif obyekti Entrybirbaşa bu xanada saxlanılacaq;

    • nextəgər bu xana artıq hansısa obyekti ehtiva edirsə, onda sahəsi -ə bərabər olan elementə təkrarlanır null. Bundan sonra bizim sinif obyektimiz Entrysiyahıda növbəti olur;

    • eyni obyekti keyyenidən əlavə etsək nə olacaq? Məntiqi olaraq, köhnə dəyəri əvəz etməlidir. Bəli, belə də olacaq. equals()İterasiya zamanı düymələr ( ) metodu ilə müqayisə ediləcək key.equals(k). Nəticə doğrudursa, köhnə dəyər cari obyektin dəyəri ilə əvəz olunacaq Entry.

Alın:

İndi isə metodun tətbiqinə nəzər salaq almaq
/**
  * 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;
 }
İndi siz put metodunun hasshmaplarda necə işlədiyini başa düşdüyünüzə görə, put metodunun necə işlədiyini başa düşmək getçox sadədir. Hash xəritəsindən dəyər əldə etmək üçün hər hansı bir açarı metoda ötürdüyünüz zaman:
  1. Bir obyekt Ekey bərabərlik üçün sınaqdan keçirilir null. Əgər belədirsə, onda xanada saxlanılan obyektin dəyəri qaytarılacaq table[0];

  2. hashcode()Açar obyektin hash kodunu hesablayan adlı metodu var ;

  3. indexFor(hash,table.length)tablesinif obyektinin götürüləcəyi xüsusi massiv xanasını müəyyən etmək üçün istifadə olunur Entry;

  4. Massiv xana nömrəsini aldıqdan sonra tableo, siyahıda təkrarlanacaq və metoddan istifadə edərək düymələri müqayisə edəcək equals(). Nəticə doğru olarsa, o zaman obyektin dəyəri qaytarılacaq Entry, əks halda - null.

Xatırlamaq lazım olanlar:

  • Sinfin açar-dəyər cütlərini saxlayan HashMapdaxili sinfi var ;Entry

  • Sinfin obyektləri adlı Entrymassivdə saxlanılır ;Entry[ ]table

  • Massiv hüceyrəsi vedrə adlanır və əlaqəli siyahının ilk elementini saxlayır;

  • hashcode()Obyekt metodu keybu sinif obyektinin vedrəsini tapmaq üçün istifadə olunur Entry;

  • Əgər iki obyektin açarı eyni hash koduna malikdirsə, onlar eyni massiv kovasında saxlanılacaq table;

  • equals()Obyektin metodu keyonun unikallığını təsdiq etmək üçün istifadə olunur;

  • Metodlar equals()hashcode()obyektlər valueümumiyyətlə istifadə edilmir.

Mənbə
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION