Le Classi Map: HashMap, TreeMap, LinkedHashMap, IdentityHashMap e EnumMap in Java
- Le principali implementazioni dell'interfaccia
Map
in Java includonoHashMap
,TreeMap
,LinkedHashMap
,IdentityHashMap
eEnumMap
. HashMap
utilizza una tabella hash per memorizzare le coppie chiave/valore, garantendo un accesso rapido.TreeMap
mantiene le coppie chiave/valore in ordine crescente delle chiavi, utilizzando una struttura ad albero.LinkedHashMap
estendeHashMap
e mantiene l'ordine di inserimento delle coppie chiave/valore.IdentityHashMap
utilizza l'uguaglianza per riferimento per confrontare le chiavi.EnumMap
è progettata per l'uso con chiavi di tipoenum
.
La Classe HashMap
La classe HashMap
estende AbstractMap
e implementa l'interfaccia Map
. Utilizza una tabella hash per memorizzare la mappa.
Questo consente al tempo di esecuzione di get()
e put()
di rimanere costante anche per insiemi di grandi dimensioni. HashMap
è una classe generica che ha questa dichiarazione:
class HashMap<K, V>
Qui, K
specifica il tipo delle chiavi, e V
specifica il tipo dei valori.
Sono definiti i seguenti costruttori:
HashMap()
HashMap(Map<? extends K, ? extends V> m)
HashMap(int capacity)
HashMap(int capacity, float loadFactor)
- La prima forma costruisce una mappa hash predefinita.
- La seconda forma inizializza la mappa hash utilizzando gli elementi di
m
. - La terza forma inizializza la capacità della mappa hash a
capacity
. - La quarta forma inizializza sia la capacità che il rapporto di riempimento della mappa hash utilizzando i suoi argomenti.
Il significato di capacità e rapporto di riempimento è lo stesso di HashSet
, descritto in precedenza. La capacità predefinita è 16. Il rapporto di riempimento predefinito è 0.75.
HashMap
implementa Map
e estende AbstractMap
. Non aggiunge alcun metodo proprio.
Bisogna notare che una mappa hash non garantisce l'ordine dei suoi elementi. Pertanto, l'ordine in cui gli elementi vengono aggiunti a una mappa hash non è necessariamente l'ordine in cui vengono letti da un iteratore.
Il seguente programma illustra un possibile uso di HashMap
. In questo esempio vengono associati dei nomi di persone a dei conti correnti (rappresentati dal saldo del conto come un intero). Si noti come viene ottenuta e utilizzata una vista-insieme.
import java.util.*;
class DemoHashMap {
public static void main(String[] args) {
// Crea una mappa hash.
Map<String, Double> hm = new HashMap<String, Double>();
// Inserisce elementi nella mappa
hm.put("Giovanni Rossi", 3434.34);
hm.put("Tommaso Bianchi", 123.22);
hm.put("Giovanna Verdi", 1378.00);
hm.put("Teodoro Neri", 99.22);
hm.put("Raffaele Bianchi", -19.08);
// Ottiene un insieme delle voci.
Set<Map.Entry<String, Double>> insieme = hm.entrySet();
// Visualizza l'insieme.
for (Map.Entry<String, Double> me : insieme) {
System.out.print(me.getKey() + ": ");
System.out.println(me.getValue());
}
System.out.println();
// Deposita 1000 nel conto di Giovanni Rossi.
double saldo = hm.get("Giovanni Rossi");
hm.put("Giovanni Rossi", saldo + 1000);
System.out.println("Nuovo saldo di Giovanni Rossi: " +
hm.get("Giovanni Rossi"));
}
}
L'output di questo programma è mostrato qui (l'ordine preciso può variare):
Giovanna Verdi: 1378.0
Raffaele Bianchi: -19.08
Giovanni Rossi: 3434.34
Tommaso Bianchi: 123.22
Teodoro Neri: 99.22
Nuovo saldo di Giovanni Rossi: 4434.34
Il programma inizia creando una mappa hash e poi aggiunge vari saldi.
Successivamente, i contenuti della mappa vengono visualizzati utilizzando una vista-insieme, ottenuta chiamando entrySet()
. Le chiavi e i valori vengono visualizzati chiamando i metodi getKey()
e getValue()
che sono definiti da Map.Entry
.
Si presti molta attenzione a come viene effettuato il deposito nel conto di Giovanni Rossi. Il metodo put()
sostituisce automaticamente qualsiasi valore preesistente che è associato con la chiave specificata con il nuovo valore. Quindi, dopo che il conto di Giovanni Rossi è aggiornato, la mappa hash conterrà ancora solo un conto "Giovanni Rossi".
La Classe TreeMap
La classe TreeMap
estende AbstractMap
e implementa l'interfaccia NavigableMap
. Crea mappe memorizzate in una struttura ad albero. Una TreeMap
fornisce un mezzo efficiente per memorizzare coppie chiave/valore in modo ordinato e consente un recupero rapido. Bisogna notare che, a differenza di una hash map, una tree map garantisce che i suoi elementi saranno ordinati in ordine crescente delle chiavi.
TreeMap
è una classe generica che ha questa dichiarazione:
class TreeMap<K, V>
Qui, K
specifica il tipo delle chiavi, e V
specifica il tipo dei valori. I seguenti costruttori TreeMap
sono definiti:
TreeMap()
TreeMap(Comparator<? super K> comp)
TreeMap(Map<? extends K, ? extends V> m)
TreeMap(SortedMap<K, ? extends V> sm)
- La prima forma costruisce una tree map vuota che sarà ordinata utilizzando l'ordine naturale delle sue chiavi.
- La seconda forma costruisce una mappa basata su albero vuota che sarà ordinata utilizzando il
Comparator
comp
. I Comparator sono discussi nelle prossime lezioni. - La terza forma inizializza una tree map con le voci da
m
, che saranno ordinate utilizzando l'ordine naturale delle chiavi. La quarta forma inizializza una tree map con le voci dasm
, che saranno ordinate nello stesso ordine dism
.
TreeMap
non ha metodi di mappa oltre a quelli specificati dall'interfaccia NavigableMap
e dalla classe AbstractMap
.
Il seguente programma rielabora l'esempio precedente in modo che utilizzi TreeMap
:
import java.util.*;
class DemoHashMap {
public static void main(String[] args) {
// Crea una mappa hash.
Map<String, Double> hm = new TreeMap<String, Double>();
// Inserisce elementi nella mappa
hm.put("Giovanni Rossi", 3434.34);
hm.put("Tommaso Bianchi", 123.22);
hm.put("Giovanna Verdi", 1378.00);
hm.put("Teodoro Neri", 99.22);
hm.put("Raffaele Bianchi", -19.08);
// Ottiene un insieme delle voci.
Set<Map.Entry<String, Double>> insieme = hm.entrySet();
// Visualizza l'insieme.
for (Map.Entry<String, Double> me : insieme) {
System.out.print(me.getKey() + ": ");
System.out.println(me.getValue());
}
System.out.println();
// Deposita 1000 nel conto di Giovanni Rossi.
double saldo = hm.get("Giovanni Rossi");
hm.put("Giovanni Rossi", saldo + 1000);
System.out.println("Nuovo saldo di Giovanni Rossi: " +
hm.get("Giovanni Rossi"));
}
}
L'output di questo programma è simile a quello mostrato per HashMap
, ma gli elementi sono ordinati in ordine alfabetico crescente delle chiavi:
Giovanna Verdi: 1378.0
Giovanni Rossi: 3434.34
Raffaele Bianchi: -19.08
Teodoro Neri: 99.22
Tommaso Bianchi: 123.22
Nuovo saldo di Giovanni Rossi: 4434.34
Si noti che TreeMap
ordina le chiavi. Tuttavia, in questo caso, sono ordinate per nome invece che per cognome. Si può alterare questo comportamento specificando un comparatore quando la mappa viene creata, come vedremo nelle prossime lezioni.
La Classe LinkedHashMap
LinkedHashMap
estende HashMap
. Mantiene una lista collegata delle voci nella mappa, nell'ordine in cui sono state inserite. Questo permette l'iterazione in ordine di inserimento sulla mappa. Cioè, quando si itera attraverso una vista-collezione di una LinkedHashMap
, gli elementi saranno restituiti nell'ordine in cui sono stati inseriti. È anche possibile creare una LinkedHashMap
che restituisce i suoi elementi nell'ordine in cui sono stati acceduti per ultimi. LinkedHashMap
è una classe generica che ha questa dichiarazione:
class LinkedHashMap<K, V>
Qui, K
specifica il tipo delle chiavi, e V
specifica il tipo dei valori.
LinkedHashMap
definisce i seguenti costruttori:
LinkedHashMap()
LinkedHashMap(Map<? extends K, ? extends V> m)
LinkedHashMap(int capacity)
LinkedHashMap(int capacity, float loadFactor)
LinkedHashMap(int capacity, float loadFactor, boolean accessOrder)
- La prima forma costruisce una
LinkedHashMap
predefinita. - La seconda forma inizializza la
LinkedHashMap
con gli elementi dam
. - La terza forma inizializza la capacità.
- La quarta forma inizializza sia la capacità che il rapporto di riempimento. Il significato di capacità e rapporto di riempimento sono gli stessi di
HashMap
. La capacità predefinita è 16. Il rapporto predefinito è 0.75. - L'ultima forma permette di specificare se gli elementi saranno memorizzati nella lista collegata per ordine di inserimento, o per ordine di ultimo accesso. Se
accessOrder
ètrue
, allora viene usato l'ordine di accesso. SeaccessOrder
èfalse
, allora viene usato l'ordine di inserimento.
LinkedHashMap
aggiunge solo un metodo a quelli definiti da HashMap
. Questo metodo è removeEldestEntry()
, ed è mostrato qui:
protected boolean removeEldestEntry(Map.Entry<K, V> e)
Questo metodo è chiamato da put()
e putAll()
. La voce più vecchia è passata in e
. Per impostazione predefinita, questo metodo restituisce false
e non fa nulla. Tuttavia, se si sovrascrive questo metodo, allora si può avere la LinkedHashMap
che rimuove la voce più vecchia nella mappa. Per fare questo, bisogna fare in modo che la sovrascrittura restituisca true
. Per mantenere la voce più vecchia, bisogna restituire false
.
La Classe IdentityHashMap
IdentityHashMap
estende AbstractMap
e implementa l'interfaccia Map
. È simile a HashMap
eccetto che usa l'uguaglianza per riferimento quando confronta gli elementi. IdentityHashMap
è una classe generica che ha questa dichiarazione:
class IdentityHashMap<K, V>
Qui, K
specifica il tipo di chiave, e V
specifica il tipo di valore. La documentazione API afferma esplicitamente che IdentityHashMap
non è per uso generale.
La Classe EnumMap
EnumMap
estende AbstractMap
e implementa Map
. È specificamente per l'uso con chiavi di tipo enum
. È una classe generica che ha questa dichiarazione:
class EnumMap<K extends Enum<K>, V>
Qui, K
specifica il tipo di chiave, e V
specifica il tipo di valore. Notare che K
deve estendere Enum<K>
, il che applica il requisito che le chiavi devono essere di tipo enum
.
EnumMap
definisce i seguenti costruttori:
EnumMap(Class<K> tipoK)
EnumMap(Map<K, ? extends V> m)
EnumMap(EnumMap<K, ? extends V> em)
- Il primo costruttore crea un
EnumMap
vuoto di tipotipoK
. - Il secondo crea una mappa
EnumMap
che contiene le stesse voci dim
. - Il terzo crea un
EnumMap
inizializzato con i valori inem
.
EnumMap
non definisce metodi propri.