get
in put
HashMap?”. Qui cercherò di spiegare la funzionalità interna utilizzando un semplice esempio. Senza addentrarci troppo nella teoria, inizieremo con un esempio in modo che possiate capire meglio e poi vedere come funzionano i metodi get
anche put
in Java . Facciamo un esempio molto semplice. Abbiamo una classe Country
("paese" inglese), utilizzeremo l'oggetto della classe Country
come chiave e il nome della capitale di questo paese come valore. Di seguito è riportato un esempio per aiutarci a capire come verrà archiviata una coppia chiave-valore in una mappa hash.
1. Paese.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;
}
}
Se vuoi capire e saperne di più su metodi hashcode
ed eguali, puoi seguire questo link .
2. HashMapStructure.java (classe principale)
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);
}
}
}
Ora imposta il punto di interruzione sulla riga 23 ed esegui run -> debug as-> java application (nota del traduttore - valido per Eclipse). Il programma interromperà l'esecuzione alla riga 23, dopodiché fare clic con il tasto destro su countryCapitalMap e selezionare watch . Vedrai una tabella come questa: Qui vediamo quanto segue:
-
Esiste un array
Entry[]
di 16 celle denominatotable
; -
Questo array memorizza gli oggetti della classe
Entry
. La classeHashMap
ha una classe interna -Entry
. E le istanze di questa classe sono coppie chiave-valore. Diamo un'occhiata alla struttura della classeEntry
: -
Ogni volta che proviamo a creare una coppia chiave-valore in una mappa hash, verrà creato un oggetto classe per quella coppia
Entry
e verrà archiviato nella tabella sopraEntry[]
. E ora ti starai chiedendo dove esattamente in questa tabella verrà scritto questo oggetto (in quale cella). Per una chiave in una coppia chiave-valore, un codice hash viene calcolato utilizzando il metodohashcode()
. E questo codice hash viene utilizzato per calcolare il numero di celle della tabellaEntry[]
; -
Ora se guardi la cella 10 della tabella, vedrai un oggetto di classe
Entry
denominatoHashMap$Entry
; - Abbiamo aggiunto 4 coppie chiave-valore, ma ce ne sono solo 2 nell'array!!! Questo perché se 2 oggetti hanno lo stesso codice hash, verranno archiviati nella stessa cella. Ma come? Gli oggetti verranno archiviati come elenco collegato (
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 имеет четное количество букв.
La figura seguente spiegherà l'idea di un elenco collegato: Ora che hai già compreso la struttura delle mappe hash, passiamo ai metodi put
e get
.
Mettere:
Vediamo come si utilizza questo metodo:/**
* Метод связывает указанное 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;
}
Ora proviamo a capire passo dopo passo questo codice:
-
Controlliamo l'
key
uguaglianza dell'oggettonull
. In tal caso, l'oggettokey
verrà archiviato nella posizionetable[0]
perché il codice hashnull
è sempre 0; -
Successivamente, chiamiamo il
key
metodo dell'oggettohashcode()
, che calcolerà il suo codice hash. Questo codice hash viene utilizzato per determinare la cella dell'array in cui verrà archiviato l'oggetto della classeEntry
. A volte capita che questa funzionehashcode
non sia scritta in modo molto abile, quindi gli sviluppatori JDK hanno creato una funzione diversa -hash()
, che prende come argomento il codice hash precedentemente calcolato. Se sei interessato a leggere più in dettaglio questa funzione, puoi seguire il collegamento ; -
indexFor(hash,table.length)
utilizzato per definire una cella specifica nell'arraytable
in cui verrà definito un oggetto di classe da archiviareEntry
; -
Come abbiamo visto nel nostro esempio, se due oggetti
key
hanno lo stesso codice hash (questa situazione è nota come collisione), verranno archiviati sotto forma di un elenco collegato. Pertanto, in questa fase iteriamo la nostra lista: -
se la cella appena calcolata è vuota, l'oggetto della classe
Entry
verrà salvato direttamente in questa cella; -
se questa cella contiene già qualche oggetto, esegue l'iterazione sull'elemento il cui campo è
next
uguale anull
. Successivamente, il nostro oggetto classeEntry
diventa il prossimo nell'elenco; -
cosa succede se aggiungiamo
key
di nuovo lo stesso oggetto? Logicamente, dovrebbe sostituire il vecchio valore. Sì, sarà così. Durante l'iterazione, le chiavi verranno confrontate utilizzando il metodoequals()
(key.equals(k)
). Se il risultato è vero, il vecchio valore verrà sostituito con il valore dell'oggetto correnteEntry
.
Ottenere:
Ora diamo un'occhiata all'applicazione del metodo/**
* 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;
}
Ora che hai capito come funziona il metodo put nelle hashmap, capire come funziona il metodo put è
get
molto semplice. Quando passi una chiave qualsiasi a un metodo per ottenere un valore da una mappa hash:
-
Un oggetto
Ekey viene testato per l'uguaglianza null
. In tal caso verrà restituito il valore dell'oggetto memorizzato nella cellatable[0]
; -
L'oggetto chiave ha un metodo chiamato
hashcode()
che calcola il codice hash; -
indexFor(hash,table.length)
utilizzato per determinare una cella specifica dell'arraytable
da cui prendere un oggetto di classeEntry
; -
Dopo aver ricevuto il numero di cella dell'array,
table
scorrerà l'elenco e confronterà le chiavi utilizzando il metodoequals()
. Se il risultato è vero, verrà restituito il valore dell'oggettoEntry
, altrimenti -null
.
Cose da ricordare:
-
La classe
HashMap
ha una classe internaEntry
che memorizza le coppie chiave-valore; -
Gli oggetti della classe
Entry
sono memorizzati in un arrayEntry[ ]
chiamatotable
; -
Una cella dell'array è chiamata bucket e memorizza il primo elemento di un elenco collegato;
-
Il metodo
hashcode()
dell'oggettokey
viene utilizzato per trovare il bucket di questo oggetto di classeEntry
; -
Se le chiavi di due oggetti hanno lo stesso codice hash, verranno archiviate nello stesso bucket di array
table
; -
Il metodo
equals()
di un oggettokey
viene utilizzato per confermarne l'unicità; -
Metodi
equals()
ehashcode()
oggettivalue
non vengono utilizzati affatto.
GO TO FULL VERSION