get
ในput
HashMap คืออะไร” ที่นี่ฉันจะพยายามอธิบายฟังก์ชันการทำงานภายในโดยใช้ตัวอย่างง่ายๆ เราจะเริ่มต้นด้วยตัวอย่างเพื่อให้คุณเข้าใจได้ดีขึ้น และดูว่าเมธอดต่างๆ ทำงานอย่างไรใน Java get
โดย ไม่ต้องลงทฤษฎีมากเกินไป put
ลองยกตัวอย่างง่ายๆ เรามีคลาส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และเลือกwatch คุณจะเห็นตารางดังนี้: ที่นี่เราเห็นดังต่อไปนี้:
-
มีอาร์เรย์
Entry[]
16 เซลล์ชื่อtable
; -
Entry
อาร์เรย์นี้เก็บ วัตถุของคลาส คลาสนี้HashMap
มีคลาสภายใน -Entry
. และอินสแตนซ์ของคลาสนี้คือคู่คีย์-ค่า มาดูโครงสร้างคลาสกันEntry
: -
ทุกครั้งที่เราพยายามสร้างคู่คีย์-ค่าในแฮชแมป ออบเจ็กต์คลาสจะถูกสร้างขึ้นสำหรับคู่นั้นและ
Entry
จะถูกเก็บไว้ในตารางด้านบนEntry[]
และตอนนี้คุณควรสงสัยว่าวัตถุนี้จะเขียนอยู่ที่ไหนในตารางนี้ (ในเซลล์ใด) สำหรับคีย์ในคู่คีย์-ค่า รหัสแฮชจะคำนวณโดยใช้รูปhashcode()
แบบ และรหัสแฮชนี้ใช้ในการคำนวณจำนวนเซลล์ในEntry[]
ตาราง -
ตอนนี้ ถ้าคุณดูที่เซลล์ 10 ของตาราง คุณจะเห็นคลาสอ็อบเจ็กต์
Entry
ชื่อHashMap$Entry
; - เราเพิ่มคู่คีย์-ค่า 4 คู่ แต่มีเพียง 2 คู่ในอาร์เรย์!!! เนื่องจากหากวัตถุ 2 ชิ้นมีรหัสแฮชเดียวกัน วัตถุเหล่านั้นก็จะถูกจัดเก็บไว้ในเซลล์เดียวกัน แต่อย่างไร? ออบเจ็กต์จะถูกจัดเก็บเป็นรายการเชื่อมโยง (
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 имеет четное количество букв.
รูปต่อไปนี้ จะ อธิบายแนวคิดของรายการที่เชื่อมโยง: เมื่อคุณมีความเข้าใจเกี่ยวกับโครงสร้างของแฮชแมปแล้ว มาดู วิธี put
และ กันดีกว่าget
ใส่:
มาดูกันว่าวิธีนี้ใช้อย่างไร:/**
* Метод связывает указанное 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;
}
ตอนนี้เรามาลองทำความเข้าใจโค้ดนี้ทีละขั้นตอน:
-
เราตรวจสอบวัตถุ
key
เพื่อความเท่าเทียมnull
กัน หากเป็นเช่นนั้น ออบเจ็กต์key
จะถูกจัดเก็บไว้ในตำแหน่งtable[0]
เนื่องจากรหัสแฮชสำหรับnull
จะเป็น 0 เสมอ -
ต่อไป เราเรียก
key
เมธอด ของอ็อบเจ็กต์hashcode()
ซึ่งจะคำนวณรหัสแฮชของมัน รหัสแฮชนี้ใช้เพื่อกำหนดเซลล์อาร์เรย์ที่จะจัดเก็บอ็อบเจ็กต์Entry
คลาส บางครั้งมันเกิดขึ้นว่าฟังก์ชันนี้hashcode
เขียนได้ไม่ชำนาญมากนัก ดังนั้นนักพัฒนา JDK จึงสร้างฟังก์ชันอื่น -hash()
ซึ่งใช้รหัสแฮชที่คำนวณไว้ก่อนหน้านี้เป็นอาร์กิวเมนต์ หากคุณสนใจอ่านรายละเอียดเกี่ยวกับฟังก์ชันนี้เพิ่มเติม โปรดไปที่ลิงก์ ; -
indexFor(hash,table.length)
ใช้เพื่อกำหนดเซลล์เฉพาะในอาร์เรย์ที่table
จะกำหนดวัตถุคลาสที่จะเก็บไว้Entry
-
ดังที่เราเห็นในตัวอย่างของเรา หากวัตถุสองชิ้น
key
มีรหัสแฮชเดียวกัน (สถานการณ์นี้เรียกว่าการชนกัน) วัตถุเหล่านั้นจะถูกจัดเก็บในรูปแบบของรายการที่เชื่อมโยง ดังนั้น ในขั้นตอนนี้ เราจึงขอย้ำรายการของเรา: -
หากเซลล์ที่คำนวณใหม่ว่างเปล่า คลาสอ็อบเจ็กต์
Entry
จะถูกบันทึกลงในเซลล์นี้โดยตรง -
หากเซลล์นี้มีวัตถุอยู่แล้ว ให้วนซ้ำองค์ประกอบที่มีฟิลด์
next
เท่ากับnull
หลังจากนี้ class object ของเราEntry
จะกลายเป็นรายการถัดไปในรายการ -
จะเกิดอะไรขึ้นถ้าเราเพิ่มวัตถุเดียวกัน
key
อีกครั้ง? ตามหลักเหตุผลแล้ว ควรแทนที่ค่าเก่า ใช่ มันจะเป็นเช่นนั้น ในระหว่างการวนซ้ำ คีย์จะถูกเปรียบเทียบโดยใช้ วิธีequals()
(key.equals(k)
) หากผลลัพธ์เป็นจริง ค่าเก่าจะถูกแทนที่ด้วยค่าของอ็อบเจ็กต์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;
}
ตอนนี้คุณเข้าใจแล้วว่าวิธีใส่ทำงานอย่างไรในแฮชแมปแล้ว การทำความเข้าใจว่าวิธีใส่ทำงานอย่างไรนั้น
get
ง่ายมาก เมื่อคุณส่งคีย์ใด ๆ ไปยังวิธีการรับค่าจากแมปแฮช:
-
วัตถุ
Ekey ได้รับการทดสอบเพื่อความเท่าเทียม null
กัน หากเป็นเช่นนั้น ค่าของออบเจ็กต์ที่เก็บไว้ในเซลล์จะถูกส่งtable[0]
กลับ -
คีย์ออบเจ็กต์มีวิธีการที่เรียกว่า
hashcode()
คำนวณรหัสแฮช -
indexFor(hash,table.length)
ใช้เพื่อกำหนดเซลล์อาร์เรย์เฉพาะtable
ที่จะใช้วัตถุEntry
คลาส -
หลังจากได้รับหมายเลขเซลล์อาร์เรย์แล้ว
table
จะวนซ้ำรายการและเปรียบเทียบคีย์โดยใช้equals()
เมธอด หากผลลัพธ์เป็นจริง ค่าของอ็อบเจ็กต์จะถูกส่งกลับEntry
มิฉะนั้นnull
-
สิ่งที่ต้องจำ:
-
คลาส
HashMap
มีคลาสภายในEntry
ที่เก็บคู่คีย์-ค่า -
วัตถุของคลาส
Entry
จะถูกเก็บไว้ในอาร์เรย์Entry[ ]
ที่เรียกว่าtable
; -
เซลล์อาร์เรย์เรียกว่าที่เก็บข้อมูลและจัดเก็บองค์ประกอบแรกของรายการที่เชื่อมโยง
-
วิธี
hashcode()
การวัตถุkey
ใช้ในการค้นหาถังของวัตถุคลาสEntry
นี้ -
หากคีย์ของวัตถุสองตัวมีรหัสแฮชเหมือนกัน คีย์เหล่านั้นจะถูกจัดเก็บไว้ในที่เก็บข้อมูลอาร์เรย์
table
เดียวกัน -
วิธีการ
equals()
ของวัตถุkey
ใช้เพื่อยืนยันเอกลักษณ์ของมัน -
วิธีการ
equals()
และhashcode()
วัตถุvalue
ไม่ได้ใช้เลย
GO TO FULL VERSION