WeakHashMap, особенности использования
WeakHashMap — это реализация интерфейса Map, которая использует слабые ссылки на ключи. Эта структура данных особенно полезна для кеширования, где не требуется жесткая ссылка на ключи, и объекты могут быть автоматически удалены сборщиком мусора, когда они больше не используются. Рассмотрим подробно особенности и использование WeakHashMap.
Основные особенности WeakHashMap
Слабые ссылки: Ключи в WeakHashMap хранятся как слабые ссылки. Это значит, что если на объект-ключ нет жестких ссылок из других объектов, то он может быть удален сборщиком мусора.
Автоматическое удаление: При удалении ключа сборщиком мусора, соответствующая пара ключ-значение также удаляется из карты.
Потокобезопасность: WeakHashMap не является потокобезопасной и требует внешней синхронизации при доступе из нескольких потоков.
Внутреннее устройство WeakHashMap
WeakHashMap основан на массиве сегментов (bucket), где каждая ячейка массива может содержать связанный список элементов, как в HashMap. Однако, ключи хранятся в виде слабых ссылок (WeakReference), что позволяет сборщику мусора удалять их при необходимости.
Примеры использования WeakHashMap
Создание и добавление элементов
Основные методы WeakHashMap
Метод put
Добавляет пару ключ-значение в карту.
Метод get
Возвращает значение, связанное с указанным ключом.
Метод remove
Удаляет запись по ключу и возвращает удаленное значение.
Метод containsKey
Проверяет, содержится ли ключ в карте.
Метод containsValue
Проверяет, содержится ли значение в карте.
Метод size
Возвращает количество элементов в карте.
Метод isEmpty
Проверяет, пуста ли карта.
Метод clear
Очищает карту, удаляя все элементы.
Особенности использования WeakHashMap
Кеширование
WeakHashMap идеально подходит для кеширования данных, которые можно восстанавливать, если они удалены сборщиком мусора. Например, кеширование изображений в приложении, где изображения могут быть загружены повторно, если они были удалены.
Автоматическое удаление
В ситуациях, когда необходимо автоматически удалять элементы карты при отсутствии ссылок на ключи, WeakHashMap будет полезен. Например, для ассоциации метаданных с объектами без предотвращения их сборки мусора.
Полезные ссылки для более полного ознакомления с WeakHashMap (спасибо авторам за их кропотливую работу):
https://www.baeldung.com/java-weakhashmap
https://javarush.com/quests/lectures/questservlets.level18.lecture08
#Java #Training #Medium #WeakHashMap
  
  WeakHashMap — это реализация интерфейса Map, которая использует слабые ссылки на ключи. Эта структура данных особенно полезна для кеширования, где не требуется жесткая ссылка на ключи, и объекты могут быть автоматически удалены сборщиком мусора, когда они больше не используются. Рассмотрим подробно особенности и использование WeakHashMap.
Основные особенности WeakHashMap
Слабые ссылки: Ключи в WeakHashMap хранятся как слабые ссылки. Это значит, что если на объект-ключ нет жестких ссылок из других объектов, то он может быть удален сборщиком мусора.
Автоматическое удаление: При удалении ключа сборщиком мусора, соответствующая пара ключ-значение также удаляется из карты.
Потокобезопасность: WeakHashMap не является потокобезопасной и требует внешней синхронизации при доступе из нескольких потоков.
Внутреннее устройство WeakHashMap
WeakHashMap основан на массиве сегментов (bucket), где каждая ячейка массива может содержать связанный список элементов, как в HashMap. Однако, ключи хранятся в виде слабых ссылок (WeakReference), что позволяет сборщику мусора удалять их при необходимости.
Примеры использования WeakHashMap
Создание и добавление элементов
import java.util.WeakHashMap;
import java.util.Map;
public class WeakHashMapExample {
public static void main(String[] args) {
WeakHashMap<String, String> weakMap = new WeakHashMap<>();
String key1 = new String("key1");
String key2 = new String("key2");
weakMap.put(key1, "value1");
weakMap.put(key2, "value2");
System.out.println("Before GC: " + weakMap);
key1 = null;
System.gc();
// Подождем немного, чтобы GC мог удалить key1
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("After GC: " + weakMap);
}
}
Основные методы WeakHashMap
Метод put
Добавляет пару ключ-значение в карту.
WeakHashMap<String, Integer> map = new WeakHashMap<>();
map.put("Apple", 50);
map.put("Banana", 30);
Метод get
Возвращает значение, связанное с указанным ключом.
Integer value = map.get("Apple");
System.out.println("Value for key 'Apple': " + value);Метод remove
Удаляет запись по ключу и возвращает удаленное значение.
Integer removedValue = map.remove("Banana");
System.out.println("Removed value: " + removedValue);Метод containsKey
Проверяет, содержится ли ключ в карте.
boolean contains = map.containsKey("Apple");
System.out.println("Contains key 'Apple': " + contains);Метод containsValue
Проверяет, содержится ли значение в карте.
boolean containsValue = map.containsValue(50);
System.out.println("Contains value 50: " + containsValue);
Метод size
Возвращает количество элементов в карте.
int size = map.size();
System.out.println("Size of the map: " + size);
Метод isEmpty
Проверяет, пуста ли карта.
boolean isEmpty = map.isEmpty();
System.out.println("Is the map empty: " + isEmpty);
Метод clear
Очищает карту, удаляя все элементы.
map.clear();
System.out.println("Size after clear: " + map.size());
Особенности использования WeakHashMap
Кеширование
WeakHashMap идеально подходит для кеширования данных, которые можно восстанавливать, если они удалены сборщиком мусора. Например, кеширование изображений в приложении, где изображения могут быть загружены повторно, если они были удалены.
Автоматическое удаление
В ситуациях, когда необходимо автоматически удалять элементы карты при отсутствии ссылок на ключи, WeakHashMap будет полезен. Например, для ассоциации метаданных с объектами без предотвращения их сборки мусора.
Полезные ссылки для более полного ознакомления с WeakHashMap (спасибо авторам за их кропотливую работу):
https://www.baeldung.com/java-weakhashmap
https://javarush.com/quests/lectures/questservlets.level18.lecture08
#Java #Training #Medium #WeakHashMap
JavaRush
  
  Курс All lectures for ru purposes - Лекция: Работа с WeakHashMap
  Знакомство с WeakHashMap. Методы в WeakHashMap. Примеры использования. Сравнение HashMap и WeakHashMap.
  Внутреннее устройство WeakHashMap
Основные компоненты
Бакеты:
WeakHashMap использует массив бакетов для хранения элементов. Каждый бакет представляет собой связанный список, который хранит элементы с одинаковым значением хэш-кода (коллизии).
Слабые ссылки (Weak References):
Ключи в WeakHashMap хранятся в виде слабых ссылок (java.lang.ref.WeakReference). Это означает, что ключи могут быть удалены сборщиком мусора, если на них больше нет жестких ссылок.
Структура записи (Entry):
Каждый элемент в WeakHashMap представлен экземпляром внутреннего класса WeakHashMap.Entry. Этот класс расширяет WeakReference<K> и содержит дополнительные поля для значения (V) и ссылки на следующий элемент в связанном списке (для коллизий).
Сборка мусора:
Сборщик мусора удаляет записи, ключи которых больше не используются. После удаления элемента его запись в бакете становится недействительной и удаляется при следующем доступе или изменении карты.
Механизм работы
Хэширование:
При добавлении элемента в карту ключ хэшируется, и результат используется для определения бакета, в который будет помещен элемент.
Добавление элементов:
Новый элемент добавляется в соответствующий бакет. Если бакет уже содержит элементы с одинаковым хэш-кодом, новый элемент добавляется в конец связанного списка.
Удаление элементов:
Когда ключ становится недоступным для приложения (не имеет жестких ссылок), сборщик мусора удаляет его запись из памяти. WeakHashMap автоматически удаляет такие записи при следующем доступе или модификации.
Примеры использования
Пример 1: Простой пример использования WeakHashMap
В этом примере мы создаем WeakHashMap и добавляем в нее две пары ключ-значение. Затем убираем жесткие ссылки на ключи и вызываем сборщик мусора. После сборки мусора элементы с ключами, на которые больше нет жестких ссылок, удаляются из карты.
Пример 2: Использование WeakHashMap для кеширования
WeakHashMap часто используется для кеширования данных, которые могут быть автоматически удалены, когда они больше не нужны. Это позволяет эффективно управлять памятью.
#Java #Training #Medium #WeakHashMap
  Основные компоненты
Бакеты:
WeakHashMap использует массив бакетов для хранения элементов. Каждый бакет представляет собой связанный список, который хранит элементы с одинаковым значением хэш-кода (коллизии).
Слабые ссылки (Weak References):
Ключи в WeakHashMap хранятся в виде слабых ссылок (java.lang.ref.WeakReference). Это означает, что ключи могут быть удалены сборщиком мусора, если на них больше нет жестких ссылок.
Структура записи (Entry):
Каждый элемент в WeakHashMap представлен экземпляром внутреннего класса WeakHashMap.Entry. Этот класс расширяет WeakReference<K> и содержит дополнительные поля для значения (V) и ссылки на следующий элемент в связанном списке (для коллизий).
Сборка мусора:
Сборщик мусора удаляет записи, ключи которых больше не используются. После удаления элемента его запись в бакете становится недействительной и удаляется при следующем доступе или изменении карты.
Механизм работы
Хэширование:
При добавлении элемента в карту ключ хэшируется, и результат используется для определения бакета, в который будет помещен элемент.
Добавление элементов:
Новый элемент добавляется в соответствующий бакет. Если бакет уже содержит элементы с одинаковым хэш-кодом, новый элемент добавляется в конец связанного списка.
Удаление элементов:
Когда ключ становится недоступным для приложения (не имеет жестких ссылок), сборщик мусора удаляет его запись из памяти. WeakHashMap автоматически удаляет такие записи при следующем доступе или модификации.
Примеры использования
Пример 1: Простой пример использования WeakHashMap
import java.util.WeakHashMap;
public class WeakHashMapExample {
public static void main(String[] args) {
WeakHashMap<String, String> map = new WeakHashMap<>();
String key1 = new String("key1");
String value1 = "value1";
map.put(key1, value1);
String key2 = new String("key2");
String value2 = "value2";
map.put(key2, value2);
System.out.println("Map before GC: " + map);
// Убираем жесткие ссылки на ключи
key1 = null;
key2 = null;
// Вызываем сборщик мусора
System.gc();
// Небольшая задержка для того, чтобы сборщик мусора успел сработать
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Map after GC: " + map);
}
}
В этом примере мы создаем WeakHashMap и добавляем в нее две пары ключ-значение. Затем убираем жесткие ссылки на ключи и вызываем сборщик мусора. После сборки мусора элементы с ключами, на которые больше нет жестких ссылок, удаляются из карты.
Пример 2: Использование WeakHashMap для кеширования
WeakHashMap часто используется для кеширования данных, которые могут быть автоматически удалены, когда они больше не нужны. Это позволяет эффективно управлять памятью.
import java.util.WeakHashMap;
public class ImageCache {
private WeakHashMap<String, byte[]> cache = new WeakHashMap<>();
public byte[] getImage(String imageName) {
byte[] image = cache.get(imageName);
if (image == null) {
image = loadImageFromDisk(imageName);
cache.put(imageName, image);
}
return image;
}
private byte[] loadImageFromDisk(String imageName) {
// Заглушка для примера, возвращаем пустой массив
return new byte[0];
}
public static void main(String[] args) {
ImageCache imageCache = new ImageCache();
byte[] image1 = imageCache.getImage("image1.png");
byte[] image2 = imageCache.getImage("image2.png");
System.out.println("Image1 loaded: " + (image1 != null));
System.out.println("Image2 loaded: " + (image2 != null));
}
}
#Java #Training #Medium #WeakHashMap
Раздел 6. Коллекции в Java
Глава 5. Map — отображения (словари)
Реализации: HashMap, LinkedHashMap, TreeMap и остальные
JCF предоставляет богатый набор реализаций Map, каждая оптимизирована под конкретные нужды.
Все они реализуют Map<K, V>, но различаются по:
Хранению: Хэш-таблица (HashMap), связный список + хэш (LinkedHashMap), красно-черное дерево (TreeMap).
Порядку: Нет (HashMap), вставки (LinkedHashMap), сортировка по ключам (TreeMap).
Производительности: O(1) для хэш, O(log n) для дерево.
Дополнительно: Специальные для enum, слабых ссылок и т.д.
1. HashMap<K, V>: Основная реализация
Описание: HashMap — сердце Map в Java, основанная на хэш-таблице. Хранит пары в массиве "бакетов" (buckets), где каждый бакет — список узлов (node) с ключом, значением и хэш-кодом.
Внутренняя структура:
Массив Node<K,V>[] table (initial capacity 16, load factor 0.75).
При put: Вычисляет hash = key.hashCode() ^ (hash >>> 16) для равномерности.
Индекс бакета: hash & (table.length - 1).
Коллизия: LinkedList или Tree (с Java 8, если > 8 узлов — дерево для O(log n)).
Ресайз: При >75% заполнения — удваивает размер, перехэширует все элементы.
Big O:
put/get/remove/containsKey: O(1) средний, O(n) worst (плохие хэши).
Итерация: O(capacity).
Особенности:
Порядок: Нет (iteration order не гарантирован).
Null: Один null-ключ, несколько null-значений.
Thread-safe: Нет (ConcurrentModificationException при параллельном доступе).
Initial capacity/load factor: new HashMap<>(16, 0.75f) для оптимизации.
Нюансы и ловушки:
hashCode/equals: Критичны! Плохой hashCode — деградация до O(n). Изменение ключа после put — потеря элемента.
Ресайз: O(n) время, но редко.
Java 8+: Tree nodes для коллизий (>8 узлов).
Remove: Если null-ключ — специальная обработка.
Итерация: entrySet(), keySet(), values() — O(capacity), не size().
Пример кода:
2. LinkedHashMap<K, V>: HashMap с порядком
Описание: Расширение HashMap с двусвязным списком для сохранения порядка вставки (insertion-order) или доступа (access-order для LRU-кэша).
Внутренняя структура: HashMap + Entry с prev/next ссылками. Два режима: INSERTION_ORDER (default) или ACCESS_ORDER (constructor flag).
Big O: O(1) для put/get/remove, как HashMap.
Особенности:
Порядок: Вставки (по умолчанию) или доступа (get/put обновляет позицию).
Null: Да.
Thread-safe: Нет.
Нюансы:
LRU кэш: new LinkedHashMap<>(16, 0.75f, true) — access-order, removeEldestEntry для eviction.
Итерация: В порядке вставки/доступа.
Ресайз: Как HashMap, но сохраняет порядок.
Пример:
#Java #для_новичков #beginner #Map #HashMap #LinkedHashMap #TreeMap #Hashtable #IdentityHashMap #EnumMap #WeakHashMap
Глава 5. Map — отображения (словари)
Реализации: HashMap, LinkedHashMap, TreeMap и остальные
JCF предоставляет богатый набор реализаций Map, каждая оптимизирована под конкретные нужды.
Все они реализуют Map<K, V>, но различаются по:
Хранению: Хэш-таблица (HashMap), связный список + хэш (LinkedHashMap), красно-черное дерево (TreeMap).
Порядку: Нет (HashMap), вставки (LinkedHashMap), сортировка по ключам (TreeMap).
Производительности: O(1) для хэш, O(log n) для дерево.
Дополнительно: Специальные для enum, слабых ссылок и т.д.
1. HashMap<K, V>: Основная реализация
Описание: HashMap — сердце Map в Java, основанная на хэш-таблице. Хранит пары в массиве "бакетов" (buckets), где каждый бакет — список узлов (node) с ключом, значением и хэш-кодом.
Внутренняя структура:
Массив Node<K,V>[] table (initial capacity 16, load factor 0.75).
При put: Вычисляет hash = key.hashCode() ^ (hash >>> 16) для равномерности.
Индекс бакета: hash & (table.length - 1).
Коллизия: LinkedList или Tree (с Java 8, если > 8 узлов — дерево для O(log n)).
Ресайз: При >75% заполнения — удваивает размер, перехэширует все элементы.
Big O:
put/get/remove/containsKey: O(1) средний, O(n) worst (плохие хэши).
Итерация: O(capacity).
Особенности:
Порядок: Нет (iteration order не гарантирован).
Null: Один null-ключ, несколько null-значений.
Thread-safe: Нет (ConcurrentModificationException при параллельном доступе).
Initial capacity/load factor: new HashMap<>(16, 0.75f) для оптимизации.
Нюансы и ловушки:
hashCode/equals: Критичны! Плохой hashCode — деградация до O(n). Изменение ключа после put — потеря элемента.
Ресайз: O(n) время, но редко.
Java 8+: Tree nodes для коллизий (>8 узлов).
Remove: Если null-ключ — специальная обработка.
Итерация: entrySet(), keySet(), values() — O(capacity), не size().
Пример кода:
javaimport java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<String, Integer> ages = new HashMap<>();
ages.put("Алексей", 35);
ages.put("Мария", 28);
ages.put("Алексей", 36); // Перезапись
System.out.println(ages.get("Алексей")); // 36
ages.put(null, 0); // Null-ключ
System.out.println(ages.size()); // 3
// Итерация
for (Map.Entry<String, Integer> entry : ages.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
}
Когда использовать: 99% случаев — быстрый поиск/кэш (userId -> User).
2. LinkedHashMap<K, V>: HashMap с порядком
Описание: Расширение HashMap с двусвязным списком для сохранения порядка вставки (insertion-order) или доступа (access-order для LRU-кэша).
Внутренняя структура: HashMap + Entry с prev/next ссылками. Два режима: INSERTION_ORDER (default) или ACCESS_ORDER (constructor flag).
Big O: O(1) для put/get/remove, как HashMap.
Особенности:
Порядок: Вставки (по умолчанию) или доступа (get/put обновляет позицию).
Null: Да.
Thread-safe: Нет.
Нюансы:
LRU кэш: new LinkedHashMap<>(16, 0.75f, true) — access-order, removeEldestEntry для eviction.
Итерация: В порядке вставки/доступа.
Ресайз: Как HashMap, но сохраняет порядок.
Пример:
javaimport java.util.LinkedHashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<String, Integer> map = new LinkedHashMap<>();
map.put("A", 1);
map.put("B", 2);
map.put("A", 3); // Обновляет, но порядок сохраняется
for (String key : map.keySet()) {
System.out.println(key); // A, B — порядок вставки
}
// Access-order
Map<String, Integer> lru = new LinkedHashMap<>(16, 0.75f, true);
lru.put("A", 1);
lru.get("A"); // "A" перемещается в конец
}
}
Когда использовать: Кэш с порядком (LRU), когда нужен predictable iteration.
#Java #для_новичков #beginner #Map #HashMap #LinkedHashMap #TreeMap #Hashtable #IdentityHashMap #EnumMap #WeakHashMap
👍1
  3. TreeMap<K, V>: Отсортированная Map
Описание: Реализация SortedMap<K, V> на красно-черном дереве (red-black tree). Ключи всегда отсортированы.
Внутренняя структура: Дерево узлов с left/right/child ссылками, цветом для баланса.
Big O: O(log n) для put/get/remove/containsKey.
Особенности:
Порядок: Сортировка по ключам (Comparable или Comparator).
Null-ключ: Нет (NPE).
Null-значение: Да.
Thread-safe: Нет.
Нюансы:
Comparator: new TreeMap<>(comparator) для custom сортировки.
Дополнительные методы: firstKey(), lastKey(), headMap(K to), tailMap(K from), subMap.
Custom ключи: Comparable<K> или Comparator.
Баланс: Автоматический, O(log n) гарантировано.
Пример:
Остальные реализации: Hashtable, IdentityHashMap, EnumMap, WeakHashMap
Hashtable<K, V> (устаревшая)
Описание: Первая Map в Java (1.0), synchronized версия HashMap.
Особенности: Thread-safe (synchronized методы), нет null, порядок нет.
Big O: O(1).
Нюансы: Медленнее HashMap (locks на каждый метод), legacy — используйте ConcurrentHashMap.
Когда: Только legacy код.
IdentityHashMap<K, V>
Описание: HashMap с == вместо equals/hashCode (по ссылке).
Особенности: Для объектов, где важна идентичность (graph algorithms).
Big O: O(1).
Нюансы: Load factor 0.5, double hash для коллизий.
Когда: Редко, для identity сравнения.
EnumMap<K extends Enum<K>, V>
Описание: Оптимизированная Map для enum ключей (массив вместо хэш).
Особенности: O(1), порядок enum, нет null-ключа.
Нюансы: Ключи — enum, values any.
Когда: State machines, enum configs.
WeakHashMap<K, V>
Описание: HashMap с weak keys (GC может удалить entry, если ключ недостижим).
Особенности: Для кэшей, где память критична.
Big O: O(1).
Нюансы: Values strong, cleanup не мгновенный.
Когда: Canonicalizing mappings (interning).
Полезные советы для новичков
HashMap 95% случаев: Начните с неё.
LinkedHashMap для кэша: removeEldestEntry для LRU.
TreeMap для сортировки: Comparator для reverse.
Custom ключи: IDE генерирует equals/hashCode.
Initial capacity: new HashMap<>(expectedSize) для избежания ресайза.
Ошибки: NPE в TreeMap с null-ключом; ClassCast в TreeMap без Comparable.
#Java #для_новичков #beginner #Map #HashMap #LinkedHashMap #TreeMap #Hashtable #IdentityHashMap #EnumMap #WeakHashMap
Описание: Реализация SortedMap<K, V> на красно-черном дереве (red-black tree). Ключи всегда отсортированы.
Внутренняя структура: Дерево узлов с left/right/child ссылками, цветом для баланса.
Big O: O(log n) для put/get/remove/containsKey.
Особенности:
Порядок: Сортировка по ключам (Comparable или Comparator).
Null-ключ: Нет (NPE).
Null-значение: Да.
Thread-safe: Нет.
Нюансы:
Comparator: new TreeMap<>(comparator) для custom сортировки.
Дополнительные методы: firstKey(), lastKey(), headMap(K to), tailMap(K from), subMap.
Custom ключи: Comparable<K> или Comparator.
Баланс: Автоматический, O(log n) гарантировано.
Пример:
javaimport java.util.TreeMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<Integer, String> map = new TreeMap<>();
map.put(3, "Три");
map.put(1, "Один");
map.put(2, "Два");
for (Integer key : map.keySet()) {
System.out.println(key + ": " + map.get(key)); // 1: Один, 2: Два, 3: Три
}
System.out.println(map.firstKey()); // 1
}
}
Когда использовать: Отсортированные ключи (диапазонные запросы, алфавитный словарь).
Остальные реализации: Hashtable, IdentityHashMap, EnumMap, WeakHashMap
Hashtable<K, V> (устаревшая)
Описание: Первая Map в Java (1.0), synchronized версия HashMap.
Особенности: Thread-safe (synchronized методы), нет null, порядок нет.
Big O: O(1).
Нюансы: Медленнее HashMap (locks на каждый метод), legacy — используйте ConcurrentHashMap.
Когда: Только legacy код.
IdentityHashMap<K, V>
Описание: HashMap с == вместо equals/hashCode (по ссылке).
Особенности: Для объектов, где важна идентичность (graph algorithms).
Big O: O(1).
Нюансы: Load factor 0.5, double hash для коллизий.
Когда: Редко, для identity сравнения.
EnumMap<K extends Enum<K>, V>
Описание: Оптимизированная Map для enum ключей (массив вместо хэш).
Особенности: O(1), порядок enum, нет null-ключа.
Нюансы: Ключи — enum, values any.
Когда: State machines, enum configs.
WeakHashMap<K, V>
Описание: HashMap с weak keys (GC может удалить entry, если ключ недостижим).
Особенности: Для кэшей, где память критична.
Big O: O(1).
Нюансы: Values strong, cleanup не мгновенный.
Когда: Canonicalizing mappings (interning).
Полезные советы для новичков
HashMap 95% случаев: Начните с неё.
LinkedHashMap для кэша: removeEldestEntry для LRU.
TreeMap для сортировки: Comparator для reverse.
Custom ключи: IDE генерирует equals/hashCode.
Initial capacity: new HashMap<>(expectedSize) для избежания ресайза.
Ошибки: NPE в TreeMap с null-ключом; ClassCast в TreeMap без Comparable.
#Java #для_новичков #beginner #Map #HashMap #LinkedHashMap #TreeMap #Hashtable #IdentityHashMap #EnumMap #WeakHashMap
👍2
  