A Collection
- czasami nazywany kontenerem - to po prostu obiekt, który grupuje wiele elementów w jedną jednostkę. Collection
S są używane do przechowywania, pobierania, manipulowania i komunikowania danych agregowanych. Struktura kolekcji W to ujednolicona architektura do reprezentowania kolekcji i manipulowania nimi.
HashMap
JDK1.2
I HashTable JDK1.0
zarówno stosuje się do oznaczania grup przedmiotów, które są reprezentowane w <Key, Value>
pary. Każda <Key, Value>
para nazywa się Entry
obiektem. Zbiór wpisów jest określany przez obiekt HashMap
i Hashtable
. Klucze w kolekcji muszą być unikalne lub charakterystyczne. [ponieważ są używane do pobierania zamapowanej wartości określonego klucza. wartości w kolekcji można powielić.]
« Członek Superclass, Legacy and Collection Framework
Hashtable to wprowadzona w starszej klasie klasa JDK1.0
, która jest podklasą klasy Dictionary. From JDK1.2
Hashtable został przeprojektowany do implementacji interfejsu Map, aby stać się członkiem frameworka kolekcji. HashMap jest członkiem Java Collection Framework od samego początku jego wprowadzenia JDK1.2
. HashMap jest podklasą klasy AbstractMap.
public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, Serializable { ... }
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable { ... }
« Początkowa wydajność i współczynnik obciążenia
Pojemność to liczba segmentów w tabeli skrótów, a początkowa pojemność to po prostu pojemność w momencie tworzenia tabeli skrótów. Zauważ, że tabela skrótów jest otwarta: w przypadku „ hash
collision
” pojedyncze wiadro przechowuje wiele wpisów, które należy kolejno przeszukiwać. Współczynnik obciążenia jest miarą tego, jak pełne jest wypełnienie tabeli mieszającej, zanim jej pojemność zostanie automatycznie zwiększona.
HashMap tworzy pustą tablicę skrótów z domyślną początkową pojemnością (16) i domyślnym współczynnikiem obciążenia (0,75). Gdzie as Hashtable konstruuje pusty hashtable z domyślną pojemnością początkową (11) i współczynnikiem obciążenia / wypełnienia (0,75).
« Modyfikacja strukturalna w przypadku zderzenia mieszającego
HashMap
, Hashtable
w przypadku kolizji skrótu przechowują wpisy map na połączonych listach. Z Java8,HashMap
jeśli wiadro skrótu przekroczy określony próg, to wiadro się zmieni linked list of entries to a balanced tree
. które poprawiają wydajność najgorszego przypadku od O (n) do O (log n). Podczas konwertowania listy na drzewo binarne kod skrótu jest używany jako zmienna rozgałęziająca. Jeśli w tym samym wiadrze znajdują się dwa różne kody skrótu, jeden jest uważany za większy i idzie na prawo od drzewa, a drugi na lewo. Ale gdy oba kody HashMap
skrótu są równe, zakłada, że klucze są porównywalne, i porównuje klucz w celu ustalenia kierunku, aby zachować pewną kolejność. Dobrą praktyką jest HashMap
porównywanie kluczy . Po dodaniu wpisów, jeśli osiągnie rozmiar wiadraTREEIFY_THRESHOLD = 8
przekonwertuj połączoną listę wpisów na zrównoważone drzewo, po usunięciu wpisów mniej niżTREEIFY_THRESHOLD
i co najwyżej UNTREEIFY_THRESHOLD = 6
przekształci zrównoważone drzewo w połączoną listę wpisów. Java 8 SRC , stosu
« Iteracja widoku kolekcji, Fast-Fast i Fail-Safe
+--------------------+-----------+-------------+
| | Iterator | Enumeration |
+--------------------+-----------+-------------+
| Hashtable | fail-fast | safe |
+--------------------+-----------+-------------+
| HashMap | fail-fast | fail-fast |
+--------------------+-----------+-------------+
| ConcurrentHashMap | safe | safe |
+--------------------+-----------+-------------+
Iterator
jest z natury szybki w działaniu. tzn. zgłasza ConcurrentModificationException, jeśli kolekcja jest modyfikowana podczas iteracji innej niż jej własna metoda remove (). Gdzie Enumeration
z natury jest bezpieczny w razie awarii. Nie rzuca żadnych wyjątków, jeśli kolekcja jest modyfikowana podczas iteracji.
Zgodnie z dokumentacją Java API Docs, Iterator jest zawsze preferowany niż wyliczanie.
UWAGA: Funkcjonalność interfejsu wyliczania jest zduplikowana przez interfejs Iteratora. Ponadto Iterator dodaje opcjonalną operację usuwania i ma krótsze nazwy metod. Nowe implementacje powinny rozważyć użycie Iteratora zamiast opcji Wyliczanie.
W Javie 5 wprowadzono interfejs ConcurrentMap : ConcurrentHashMap
- wysoce współbieżna, wysokowydajna ConcurrentMap
implementacja wspierana przez tablicę skrótów. Ta implementacja nigdy nie blokuje się podczas pobierania danych i pozwala klientowi wybrać poziom współbieżności dla aktualizacji. Ma on zastąpić drop-in dla Hashtable
: oprócz implementacji ConcurrentMap
, obsługuje wszystkie specyficzne dla niego „starsze” metody Hashtable
.
Każda HashMapEntry
wartość jest lotna, zapewniając w ten sposób drobną spójność ziarna dla spornych modyfikacji i kolejnych odczytów; każdy odczyt odzwierciedla najnowszą ukończoną aktualizację
Iteratory i wyliczenia są bezpieczne w razie awarii - odzwierciedlając stan w pewnym momencie od utworzenia iteratora / wyliczenia; pozwala to na jednoczesne odczyty i modyfikacje kosztem zmniejszonej spójności. Nie zgłaszają wyjątku ConcurrentModificationException. Jednak iteratory są zaprojektowane do użycia tylko przez jeden wątek na raz.
Podobnie, Hashtable
ale w przeciwieństwie do HashMap
tej klasy, nie pozwala na użycie wartości null jako klucza lub wartości.
public static void main(String[] args) {
//HashMap<String, Integer> hash = new HashMap<String, Integer>();
Hashtable<String, Integer> hash = new Hashtable<String, Integer>();
//ConcurrentHashMap<String, Integer> hash = new ConcurrentHashMap<>();
new Thread() {
@Override public void run() {
try {
for (int i = 10; i < 20; i++) {
sleepThread(1);
System.out.println("T1 :- Key"+i);
hash.put("Key"+i, i);
}
System.out.println( System.identityHashCode( hash ) );
} catch ( Exception e ) {
e.printStackTrace();
}
}
}.start();
new Thread() {
@Override public void run() {
try {
sleepThread(5);
// ConcurrentHashMap traverse using Iterator, Enumeration is Fail-Safe.
// Hashtable traverse using Enumeration is Fail-Safe, Iterator is Fail-Fast.
for (Enumeration<String> e = hash.keys(); e.hasMoreElements(); ) {
sleepThread(1);
System.out.println("T2 : "+ e.nextElement());
}
// HashMap traverse using Iterator, Enumeration is Fail-Fast.
/*
for (Iterator< Entry<String, Integer> > it = hash.entrySet().iterator(); it.hasNext(); ) {
sleepThread(1);
System.out.println("T2 : "+ it.next());
// ConcurrentModificationException at java.util.Hashtable$Enumerator.next
}
*/
/*
Set< Entry<String, Integer> > entrySet = hash.entrySet();
Iterator< Entry<String, Integer> > it = entrySet.iterator();
Enumeration<Entry<String, Integer>> entryEnumeration = Collections.enumeration( entrySet );
while( entryEnumeration.hasMoreElements() ) {
sleepThread(1);
Entry<String, Integer> nextElement = entryEnumeration.nextElement();
System.out.println("T2 : "+ nextElement.getKey() +" : "+ nextElement.getValue() );
//java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextNode
// at java.util.HashMap$EntryIterator.next
// at java.util.Collections$3.nextElement
}
*/
} catch ( Exception e ) {
e.printStackTrace();
}
}
}.start();
Map<String, String> unmodifiableMap = Collections.unmodifiableMap( map );
try {
unmodifiableMap.put("key4", "unmodifiableMap");
} catch (java.lang.UnsupportedOperationException e) {
System.err.println("UnsupportedOperationException : "+ e.getMessage() );
}
}
static void sleepThread( int sec ) {
try {
Thread.sleep( 1000 * sec );
} catch (InterruptedException e) {
e.printStackTrace();
}
}
« Klucze zerowe i wartości zerowe
HashMap
dopuszcza maksymalnie jeden klucz zerowy i dowolną liczbę wartości zerowych. Gdzie as Hashtable
nie zezwala nawet na pojedynczy klucz zerowy i zerową wartość, jeśli klucz lub wartość zerowa jest, wówczas zgłasza wyjątek NullPointerException. Przykład
« Zsynchronizowany, bezpieczny dla wątków
Hashtable
jest wewnętrznie zsynchronizowany. Dlatego bardzo bezpieczne jest stosowanie Hashtable
w aplikacjach wielowątkowych. Gdzie HashMap
nie jest wewnętrznie zsynchronizowany. Dlatego stosowanie HashMap
w aplikacjach wielowątkowych bez zewnętrznej synchronizacji nie jest bezpieczne . Możesz zewnętrznie synchronizować HashMap
za pomocą Collections.synchronizedMap()
metody.
« Wydajność
Ponieważ Hashtable
jest zsynchronizowany wewnętrznie, powoduje to, że jest Hashtable
nieco wolniejszy niż HashMap
.
@Widzieć