A Collection
- иногда называемый контейнером - это просто объект, который группирует несколько элементов в одну единицу. Collection
s используются для хранения, извлечения, обработки и передачи агрегированных данных. Структура коллекций W - это унифицированная архитектура для представления и управления коллекциями.
HashMap
JDK1.2
и Hashtable JDK1.0
, оба используются для представления группы объектов, представленных в паре <Key, Value>
. Каждая пара <Key, Value>
называется Entry
объектом. Коллекция записей ссылается на объект HashMap
и Hashtable
. Ключи в коллекции должны быть уникальными или отличительными. [поскольку они используются для получения сопоставленного значения определенного ключа. значения в коллекции могут быть продублированы.]
« Элемент инфраструктуры суперкласса, Legacy и Collection
Hashtable - это устаревший класс, представленный в JDK1.0
, который является подклассом класса Dictionary. С JDK1.2
Hashtable перепроектирован для реализации интерфейса Map , чтобы сделать его частью структуры коллекции. HashMap является членом Java Collection Framework с самого начала его появления в JDK1.2
. HashMap является подклассом класса 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 { ... }
« Начальная емкость и коэффициент нагрузки
Емкость - это количество сегментов в хэш-таблице, а начальная емкость - это просто емкость на момент создания хеш-таблицы. Обратите внимание, что хэш-таблица открыта: в случае «hash
collision
» в одном сегменте хранится несколько записей, которые необходимо искать последовательно. Коэффициент загрузки - это мера того, насколько полной хеш-таблице разрешено получать до автоматического увеличения ее емкости.
HashMap создает пустую хеш-таблицу с начальной емкостью по умолчанию (16) и коэффициентом загрузки по умолчанию (0,75). Где в качестве Hashtable создается пустая таблица с начальной емкостью по умолчанию (11) и коэффициентом загрузки / коэффициентом заполнения (0,75).
« Структурная модификация в случае столкновения хеша
HashMap
, Hashtable
в случае коллизий хешей они сохраняют записи карты в связанных списках. Из Java8 для HashMap
, если объем хеш-памяти превышает определенный порог, этот сегмент переключится с linked list of entries to a balanced tree
. которые улучшают производительность в худшем случае с O (n) до O (log n). При преобразовании списка в двоичное дерево хеш-код используется как переменная ветвления. Если в одном сегменте находятся два разных хэш-кода, один считается больше и идет справа от дерева, а другой - слева. Но когда оба хеш-кода равны, HashMap
предполагает, что ключи сравнимы, и сравнивает ключ, чтобы определить направление, чтобы можно было поддерживать некоторый порядок. Хорошей практикой является сопоставление ключей HashMap
. При добавлении записей, если размер сегмента достигает TREEIFY_THRESHOLD = 8
, преобразовать связанный список записей в сбалансированное дерево, при удалении записей, меньших TREEIFY_THRESHOLD
и не более UNTREEIFY_THRESHOLD = 6
, преобразовать сбалансированное дерево в связанный список записей. Java 8 SRC , стека
« Итерация в режиме сбора данных, Fail-Fast и Fail-Safe
+--------------------+-----------+-------------+
| | Iterator | Enumeration |
+--------------------+-----------+-------------+
| Hashtable | fail-fast | safe |
+--------------------+-----------+-------------+
| HashMap | fail-fast | fail-fast |
+--------------------+-----------+-------------+
| ConcurrentHashMap | safe | safe |
+--------------------+-----------+-------------+
Iterator
является безотказным по своей природе. то есть он генерирует исключение ConcurrentModificationException, если коллекция модифицируется при выполнении итерации, отличной от собственного метода remove (). Где, как Enumeration
является отказоустойчивым по своей природе. Он не выдает никаких исключений, если коллекция изменяется во время итерации.
Согласно Java API Docs, Iterator всегда предпочтительнее, чем Enumeration.
ПРИМЕЧАНИЕ: Функциональность интерфейса Enumeration дублируется интерфейсом Iterator. Кроме того, Iterator добавляет необязательную операцию удаления и имеет более короткие имена методов. Новые реализации должны рассмотреть возможность использования Iterator вместо Enumeration.
В Java 5 представила интерфейс ConcurrentMap : ConcurrentHashMap
- высококонкурентная, высокопроизводительная реализация ConcurrentMap
, поддерживаемая хеш-таблицей. Эта реализация никогда не блокируется при выполнении поиска и позволяет клиенту выбирать уровень параллелизма для обновлений. Он предназначен для замены Hashtable
: в дополнение к реализации ConcurrentMap
он поддерживает все "устаревшие" методы, характерные для Hashtable
.
Каждое значение HashMapEntry
s равно volatile , обеспечивая тем самым высокую однородность зерна для предполагаемых изменений и последующих считываний; каждое чтение отражает последнее завершенное обновление
Итераторы и перечисления являются отказоустойчивыми - отражают состояние в некоторый момент с момента создания итератора / перечисления; это позволяет одновременно считывать и модифицировать за счет снижения согласованности. Они не генерируют ConcurrentModificationException. Однако итераторы предназначены для использования только одним потоком за один раз.
Как и Hashtable
, но, в отличие от HashMap
, этот класс не позволяет использовать null в качестве ключа или значения.
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();
}
}
« Нулевые ключи и нулевые значения
HashMap
допускает максимум один нулевой ключ и любое количество нулевых значений. Где, поскольку Hashtable
не допускает даже один нулевой ключ и нулевое значение, если ключ или значение null, то он генерирует исключение NullPointerException. * ** 1 174 +1175 * * Пример 1 176 ** * 1 178
« Синхронизировано, Потокобезопасен
Hashtable
внутренне синхронизировано. Поэтому очень безопасно использовать Hashtable
в многопоточных приложениях. Где, как HashMap
не внутренне синхронизированы. Поэтому использование HashMap
в многопоточных приложениях без внешней синхронизации небезопасно. Вы можете внешне синхронизировать HashMap
, используя метод Collections.synchronizedMap()
.
« Производительность
Поскольку Hashtable
является внутренней синхронизацией, это делает Hashtable
немного медленнее, чем HashMap
.
@ See