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 get
qanday ishlashini ko'rishingiz mumkin. put
Keling, juda oddiy misolni olaylik. Bizda sinf (inglizcha "mamlakat") bor , biz kalit sifatida sinf ob'ektini va qiymat sifatida ushbu mamlakat poytaxti nomidan Country
foydalanamiz . Country
Quyida 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: Bu erda biz quyidagilarni ko'ramiz:
-
Entry[]
nomli 16 ta hujayradan iborat massiv mavjudtable
; -
Ushbu massiv sinf ob'ektlarini saqlaydi
Entry
. SinfningHashMap
ichki sinfi bor -Entry
. Va bu sinfning misollari kalit-qiymat juftliklari. Keling, sinf tuzilishini ko'rib chiqaylikEntry
: -
Har safar xesh xaritasida kalit-qiymat juftligini yaratishga harakat qilganimizda, ushbu juftlik uchun sinf ob'ekti yaratiladi
Entry
va u yuqoridagi jadvalda saqlanadiEntry[]
. 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 chiqiladihashcode()
. Va bu xesh-kod jadval hujayra raqamini hisoblash uchun ishlatiladiEntry[]
; -
Entry
Endi, agar siz jadvalning 10-hujayrasini ko'rsangiz, nomli sinf ob'ektini ko'rasizHashMap$Entry
; - 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
.
static class Entry implements Map.Entry
{
final K key;
V value;
Entry next;
final int hash;
...//продолжение 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 имеет четное количество букв.
Quyidagi rasm bog'langan ro'yxat g'oyasini tushuntiradi: Endi siz xesh xaritalar tuzilishi haqida allaqachon tushunchaga ega bo'lganingizdan so'ng, va usullariga o'tamiz . put
get
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:
-
key
Ob'ektni tenglik uchun tekshiramiznull
. Agar shunday bo'lsa, u holda ob'ektkey
joyida saqlanaditable[0]
, chunki uchun xesh kodinull
har doim 0; -
Keyinchalik, biz ob'ekt
key
usulini chaqiramizhashcode()
, bu uning xesh kodini hisoblab chiqadi. Ushbu xesh kodi sinf ob'ekti saqlanadigan qator katakchasini aniqlash uchun ishlatiladiEntry
. Ba'zan shunday bo'ladiki, bu funksiyahashcode
unchalik mohirlik bilan yozilmagan, shuning uchun JDK ishlab chiquvchilarihash()
argument sifatida ilgari hisoblangan xesh-kodni oladigan boshqa funktsiyani - yaratdilar. Agar siz ushbu funktsiya haqida batafsilroq o'qishga qiziqsangiz, havolaga o'tishingiz mumkin ; -
indexFor(hash,table.length)
table
sinf ob'ekti saqlanadigan aniqlangan qatordagi ma'lum bir hujayrani aniqlash uchun ishlatiladiEntry
; -
Bizning misolimizda ko'rganimizdek, agar ikkita ob'ekt
key
bir 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
Entry
to'g'ridan-to'g'ri ushbu katakchaga saqlanadi; -
next
agar bu katak allaqachon ob'ektni o'z ichiga olgan bo'lsa, u holda maydoni ga teng bo'lgan elementga takrorlanadinull
. Shundan so'ng, bizning sinf ob'ektimizEntry
ro'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 taqqoslanadikey.equals(k)
. Agar natija rost bo'lsa, eski qiymat joriy ob'ektning qiymati bilan almashtiriladiEntry
.
Oling:
Endi usulning qo'llanilishini ko'rib chiqamiz/**
* 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
get
juda oddiy. Xesh xaritasidan qiymat olish usuliga biron-bir kalitni uzatganingizda:
-
Ob'ekt
Ekey tenglik uchun sinovdan o'tkaziladi null
. Agar shunday bo'lsa, u holda hujayrada saqlangan ob'ektning qiymati qaytariladitable[0]
; -
Kalit ob'ektda
hashcode()
xesh kodini hisoblaydigan usul mavjud; -
indexFor(hash,table.length)
table
sinf ob'ekti olinadigan muayyan massiv katakchasini aniqlash uchun ishlatiladiEntry
; -
Massiv katak raqamini olgandan so'ng,
table
u ro'yxat bo'ylab takrorlanadi va usul yordamida kalitlarni solishtiradiequals()
. Agar natija rost bo'lsa, u holda ob'ektning qiymati qaytariladiEntry
, aks holda -null
.
Esda tutish kerak bo'lgan narsalar:
-
Sinfda kalit-qiymat juftliklarini saqlaydigan
HashMap
ichki sinf mavjud ;Entry
-
Sinf ob'ektlari deb nomlangan
Entry
massivda saqlanadi ;Entry[ ]
table
-
Massiv katakchasi chelak deb ataladi va ulangan ro'yxatning birinchi elementini saqlaydi;
-
hashcode()
Ob'ekt usulikey
bu sinf ob'ektining paqirini topish uchun ishlatiladiEntry
; -
Agar ikkita ob'ektning kalitlari bir xil xesh-kodga ega bo'lsa, ular bir xil massiv paqirida saqlanadi
table
; -
equals()
Ob'ekt usulikey
uning o'ziga xosligini tasdiqlash uchun ishlatiladi; -
Usullar
equals()
vahashcode()
ob'ektlarvalue
umuman ishlatilmaydi.
GO TO FULL VERSION