JavaRush /Java блогу /Random-KY /HashMap Javaда кантип иштейт?
gnev
Деңгээл

HashMap Javaда кантип иштейт?

Группада жарыяланган
HashMap Javaда кантип иштейт?  - 1Көбүнчө интервьюларда алар " Java'да HashMap кантип иштейт?" get”, “ HashMapда методдор кантип иштешинин ички механизми кандай put?”. Бул жерде мен жөнөкөй мисал аркылуу ички функцияларды түшүндүрүүгө аракет кылам. Өтө көп теорияга кирбестен, биз бир мисал менен баштайбыз, андыктан сиз жакшыраак түшүнүп, андан кийин Java'да методдор кандай иштээрин көрө getаласыз put. Келгиле, абдан жөнөкөй бир мисалды алалы. Бизде класс бар (англисче "өлкө"), ачкыч катары класс an objectисин, ал эми маани катары бул өлкөнүн борборунун атын Countryколдонобуз . CountryТөмөндө ачкыч-маани жуптары хэш картада кантип сакталаарын түшүнүүгө жардам берген мисал келтирилген.

1. Өлкө.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;
 }
}
Методдор жана бирдейликтер жөнүндө көбүрөөк түшүнгүңүз жана билгиңиз келсе , бул шилтемегеhashcode кирсеңиз болот .

2. HashMapStructure.java(негизги класс)

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);
            }
        }
}
Эми токтотуу чекин 23-сапка коюп, run -> debug as-> java тиркемесин иштетиңиз (котормочунун эскертүүсү - Eclipse үчүн жарактуу). Программа 23-сапта аткарууну токтотот, андан кийин countryCapitalMapти оң баскыч менен чыкылдатып, саатты тандаңыз . Сиз төмөнкүдөй tableны көрөсүз: HashMap Javaда кантип иштейт?  - 2Бул жерде биз төмөнкүлөрдү көрөбүз:
  1. Entry[]аттуу 16 клеткадан турган массив бар table;

  2. Бул массив класстын an objectтерин сактайт Entry. Класстын HashMapички классы бар - Entry. Жана бул класстын мисалдары ачкыч-маани жуптары. Класстын түзүлүшүн карап көрөлү Entry:

  3. static class Entry implements Map.Entry
            {
                    final K key;
                    V value;
                    Entry next;
                    final int hash;
                    ...//продолжение codeа
            }
  4. Биз хэш картада ачкыч-маани жуптарын түзүүгө аракет кылган сайын, ал жуп үчүн класс an objectи түзүлөт Entryжана ал жогорудагы tableда сакталат Entry[]. Эми сиз бул tableда бул an object так кайсы жерде (кайсы уячада) жазылат деп ойлонуп жатсаңыз керек. Ачкыч-маани жуптарындагы ачкыч үчүн хэш codeу hashcode(). Жана бул хэш-code столдун клетка номерин эсептөө үчүн колдонулат Entry[];

  5. Эми tableнын 10-уячасын карасаңыз, класстын an objectисин Entryкөрөсүз HashMap$Entry;

  6. Биз 4 ачкыч-маани жуптарын коштук, бирок массивде 2 гана бар!!! Себеби, эгерде 2 an objectтин хэш-codeу бирдей болсо, анда алар бир уячада сакталат. Бирок кантип? Объекттер шилтемеленген тизме ( ) катары сакталат LinkedList.
Бул жерде биздин ачкыч-маани жуптарыбыз үчүн хэш-code кантип эсептелет.
Hashcode for Japan = 95 так How длина слова Japan имеет нечетное количество букв.
Hashcode for India = 95 так How длина слова India имеет нечетное количество букв.
HashCode for Russia = 31 так How длина слова Russia имеет четное количество букв.
HashCode for France = 31 так How длина слова France имеет четное количество букв.
Төмөнкү сүрөт шилтемеленген тизменин идеясын түшүндүрөт: Эми сиз хэш карталардын түзүмү жөнүндө түшүнүккө ээ болгондон кийин, келгиле жана HashMap Javaда кантип иштейт?  - 3методдорго өтөбүз . putget

Кою:

Келгиле, бул ыкма кандайча колдонуларын карап көрөлү:
/**
  * Метод связывает указанное 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;
 }
Эми бул codeду этап-этабы менен түшүнүүгө аракет кылалы:
  1. keyОбъекттин теңдигин текшеребиз null. Эгер ошондой болсо, анда an object keyжайгашкан жерде сакталат, table[0]анткени хэш codeу nullдайыма 0;

  2. Андан кийин, биз анын хэш codeун эсептей турган an objectтин keyыкмасын чакырабыз. hashcode()Бул хэш-code класс an objectи сактала турган массив уячасын аныктоо үчүн колдонулат Entry. Кээде бул функция hashcodeөтө чебер жазылган эмес, ошондуктан JDK иштеп чыгуучулар hash()аргумент катары мурда эсептелген хэш-codeду алган башка функцияны - түзүшкөн. Эгер сиз бул функция жөнүндө кененирээк окугуңуз келсе, шилтемеге өтсөңүз болот ;

  3. indexFor(hash,table.length)tableкласс an objectи сактала турган аныктала турган массивдеги белгилүү бир уячаны аныктоо үчүн колдонулат Entry;

  4. Биздин мисалда көргөндөй, эки an objectтин keyхэш-codeу бирдей болсо (бул жагдай кагылышуу катары белгилүү), анда алар байланышкан тизме түрүндө сакталат. Ошондуктан, бул этапта биз тизмени кайталайбыз:

    • эгерде жаңы эсептелген уяча бош болсо, класс an objectи Entryтүздөн-түз ушул уячага сакталат;

    • nextэгерде бул уяча мурунтан эле кандайдыр бир an objectти камтыса, анда талаасы ге барабар болгон элементке кайталанат null. Андан кийин, биздин класс an objectи Entryтизмеде кийинки болуп калат;

    • ошол эле an objectти кайра кошсок эмне болот key? Логикалык жактан алганда, ал эски маанини алмаштыруу керек. Ооба, ошондой болот. equals()Итерация учурунда баскычтар ( ) ыкмасы менен салыштырылат key.equals(k). Эгерде натыйжа чын болсо, анда эски маани учурдагы an objectтин мааниси менен алмаштырылат Entry.

алуу:

Эми методдун колдонулушун карап көрөлү алуу
/**
  * 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;
 }
Эми сиз put методу хэшмаптарда кантип иштээрин түшүнгөнүңүздөн кийин, put ыкмасы кантип иштээрин түшүнүү getабдан жөнөкөй. Хэш картадан маани алуу үчүн методго каалаган ачкычты өткөрүп бергенде:
  1. Объект Экей теңдик үчүн сыналат null. Эгер ошондой болсо, анда уячада сакталган an objectтин мааниси кайтарылат table[0];

  2. hashcode()Негизги an objectтин хэш codeун эсептеген ыкмасы бар ;

  3. indexFor(hash,table.length)tableкласс an objectисин алуу үчүн белгилүү бир массив уячасын аныктоо үчүн колдонулат Entry;

  4. Массив уячасынын номерин алгандан кийин, tableал тизме боюнча кайталанат жана методдун жардамы менен баскычтарды салыштырат equals(). Эгерде натыйжа чын болсо, анда an objectтин мааниси кайтарылат Entry, антпесе - null.

Эсте турган нерселер:

  • Класста ачкыч-маани жуптарын сактаган HashMapички класс бар ;Entry

  • Класстын an objectтери деп аталган Entryмассивде сакталат ;Entry[ ]table

  • Массив уячасы чака деп аталат жана байланышкан тизменин биринчи элементин сактайт;

  • hashcode()Объект ыкмасы keyбул класстын an objectинин чакасын табуу үчүн колдонулат Entry;

  • Эгерде эки an objectтин ачкычтары бирдей хэш-codeго ээ болсо, алар бир эле массив чакасында сакталат table;

  • equals()Объекттин ыкмасы keyанын уникалдуулугун тастыктоо үчүн колдонулат;

  • методдору equals()жана hashcode()an objectилери valueтакыр колдонулbyte.

Булак
Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION