get
”,“HashMap中方法工作的內部機制是什麼put
?”。在這裡我將嘗試使用一個簡單的範例來解釋內部功能。在不涉及太多理論的情況下,我們將從一個範例開始,以便您可以更好地理解並了解方法在 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 application(譯者註-對Eclipse有效)。程式將在第 23 行停止執行,之後右鍵單擊CountryCapitalMap並選擇watch。您將看到這樣的表格: 這裡我們看到以下內容:
-
有一個包含
Entry[]
16 個單元格的數組,名為table
; -
該數組儲存該類別的物件
Entry
。該類別HashMap
有一個內部類別 -Entry
。該類別的實例是鍵值對。讓我們來看看類別結構Entry
: -
每次我們嘗試在哈希映射中創建鍵值對時,都會為該對創建一個類對象
Entry
,並將其存儲在上表中Entry[]
。現在您應該想知道該物件將準確寫入該表中的哪個位置(在哪個儲存格中)。對於鍵值對中的鍵,使用 計算雜湊碼hashcode()
。這個哈希碼用於計算表單元格數量Entry[]
; -
現在,如果您查看表格的儲存格 10,您將看到一個
Entry
名為 的類別物件HashMap$Entry
; - 我們新增了 4 個鍵值對,但數組中只有 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
。之後,我們的類別物件Entry
成為列表中的下一個; -
如果我們再次加入同一個物件怎麼辦
key
?從邏輯上講,它應該替換舊值。是的,會這樣。equals()
在迭代過程中,將使用( ) 方法對鍵進行比較key.equals(k)
。如果結果為 true,則舊值將被目前物件的值取代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
非常簡單了。當您將任何鍵傳遞給方法以從哈希映射中獲取值時:
-
一個東西
Ekey 被測試是否相等 null
。如果是,則傳回儲存在儲存格中的物件的值table[0]
; -
密鑰物件有一個稱為
hashcode()
計算哈希碼的方法; -
indexFor(hash,table.length)
table
用於確定從中獲取類別物件的特定數組單元Entry
; -
收到數組單元格編號後,
table
它將迭代列表並使用方法比較鍵equals()
。如果結果為 true,則傳回該物件的值Entry
,否則傳回 -null
。
要記住的事:
-
該類別
HashMap
有一個Entry
儲存鍵值對的內部類別; -
該類別的物件
Entry
儲存在一個Entry[ ]
名為 的陣列中table
; -
數組單元稱為桶,儲存鍊錶的第一個元素;
-
hashcode()
object方法key
用於尋找該類別物件的桶Entry
; -
如果兩個物件的key具有相同的雜湊碼,則它們將被儲存在同一個陣列桶中
table
; -
equals()
對象的方法key
用以確認其唯一性; -
根本不使用方法
equals()
和hashcode()
物件。value
GO TO FULL VERSION