Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# Классы наследники Map в Java
Что такое Map
Map — это интерфейс, представляющий структуру данных, которая хранит пары ключ-значение. Каждый ключ должен быть уникален, а значение может быть null.
Map<String, Integer> map = new HashMap<>();
map.put("apple", 5); // key="apple", value=5
map.put("banana", 3); // key="banana", value=3
Integer count = map.get("apple"); // 5
map.remove("banana");
HashMap — самый используемый
Основная реализация Map, основанная на хеш-таблице. Не упорядочена, работает быстро.
Map<String, String> map = new HashMap<>();
map.put("Java", "Object-oriented");
map.put("Python", "Dynamic");
map.put("Go", "Concurrent");
// Порядок итерации может быть любым
for (String lang : map.keySet()) {
System.out.println(lang); // Может быть Python, Java, Go
}
// Время операций: O(1) в среднем
map.get("Java"); // O(1)
map.put("Rust", ""); // O(1)
map.remove("Go"); // O(1)
Характеристики:
- Несинхронизированная (не thread-safe)
- Быстрая (O(1) для основных операций)
- Может быть null ключ и значения
TreeMap — упорядоченная по ключам
Основана на красно-чёрном дереве, ключи всегда отсортированы.
Map<String, Integer> map = new TreeMap<>();
map.put("zebra", 3);
map.put("apple", 5);
map.put("banana", 2);
// Итерация в порядке сортировки ключей
for (String key : map.keySet()) {
System.out.println(key);
// Вывод: apple, banana, zebra
}
// Дополнительные методы
String first = map.firstKey(); // "apple"
String last = map.lastKey(); // "zebra"
map.headMap("c"); // Всё до "c"
map.tailMap("b"); // Всё с "b"
map.subMap("a", "m"); // От "a" до "m"
// Время операций: O(log n)
map.get("apple"); // O(log n)
map.put("orange", 4); // O(log n)
Характеристики:
- Отсортирована по ключам
- Медленнее HashMap (O(log n))
- Не может быть null ключ, но может быть null значение
- Требует сравнимости ключей (Comparable или Comparator)
LinkedHashMap — упорядоченная по порядку добавления
Основана на HashMap, но сохраняет порядок вставки элементов.
Map<String, Integer> map = new LinkedHashMap<>();
map.put("first", 1);
map.put("second", 2);
map.put("third", 3);
// Итерация в порядке добавления
for (String key : map.keySet()) {
System.out.println(key);
// Вывод: first, second, third
}
// LRU (Least Recently Used) кэш
map = new LinkedHashMap<>(16, 0.75f, true) { // true = access order
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > 3; // Максимум 3 элемента
}
};
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
map.put("d", 4); // "a" будет удалён (самый старый)
Характеристики:
- Сохраняет порядок добавления или доступа
- Немного медленнее HashMap из-за двусвязного списка
- Идеален для реализации LRU кэшей
- Может быть null ключ и значения
Hashtable — устаревшая синхронизированная
Старая реализация, синхронизирована, но медленнее ConcurrentHashMap.
Map<String, Integer> map = new Hashtable<>();
map.put("a", 1);
map.put("b", 2);
// Thread-safe, но весь метод синхронизирован
Integer value = map.get("a");
// ❌ Не используй! Используй ConcurrentHashMap
Характеристики:
- Синхронизирована полностью
- Медленная (весь метод заблокирован)
- Не может быть null ключ
- Наследуется из Dictionary (устаревший класс)
ConcurrentHashMap — современная многопоточная
Оптимизирована для параллельного доступа с помощью bucket-level блокировок.
Map<String, Integer> map = new ConcurrentHashMap<>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
// Thread-safe без блокировки всей таблицы
Integer value = map.get("a");
// Несколько потоков могут одновременно писать в разные бакеты
ExecutorService executor = Executors.newFixedThreadPool(4);
for (int i = 0; i < 100; i++) {
final int idx = i;
executor.submit(() -> map.put("key" + idx, idx));
}
// Атомарные операции
map.putIfAbsent("d", 4);
map.remove("a", 1); // Удалить только если значение == 1
map.replace("b", 2, 20); // Заменить только если текущее значение == 2
// Итерация не блокирует другие потоки
for (String key : map.keySet()) {
System.out.println(key);
}
Характеристики:
- Thread-safe с segment-level блокировками
- Быстра для многопоточного доступа
- Не может быть null ключ, но может быть null значение
- Идеальна для приложений с высоким параллелизмом
WeakHashMap — для автоматической очистки
Использует слабые ссылки на ключи, позволяя сборщику мусора удалять элементы.
Map<String, String> map = new WeakHashMap<>();
String key = "important";
map.put(key, "value");
System.out.println(map.size()); // 1
key = null; // Ключ больше не используется
System.gc(); // Принудительная очистка мусора
System.out.println(map.size()); // Может быть 0
// Полезна для кэшей
Map<Class<?>, ClassMetadata> classMetadataCache = new WeakHashMap<>();
classMetadataCache.put(String.class, new ClassMetadata());
// Когда класс выгружается, запись в кэше автоматически удалится
Характеристики:
- Ключи могут быть удалены сборщиком мусора
- Полезна для кэшей и памяти
- Медленнее HashMap
IdentityHashMap — по идентичности, не по equals
Использует == вместо equals() для сравнения ключей.
Map<String, String> map = new IdentityHashMap<>();
String key1 = new String("hello");
String key2 = new String("hello");
map.put(key1, "value1");
map.put(key2, "value2");
System.out.println(map.size()); // 2 (не 1!)
// Потому что key1 и key2 — разные объекты (== вернёт false)
map.get(key1); // "value1"
map.get(key2); // "value2"
map.get("hello"); // null (не equals ни одному ключу)
Характеристики:
- Сравнивает по идентичности (==), не по equals
- Очень быстрая
- Редко используется
EnumMap — оптимизирована для enum ключей
Оптимизирована специально для использования enum в качестве ключей.
enum Color { RED, GREEN, BLUE }
Map<Color, String> map = new EnumMap<>(Color.class);
map.put(Color.RED, "#FF0000");
map.put(Color.GREEN, "#00FF00");
map.put(Color.BLUE, "#0000FF");
// Очень быстро и эффективно по памяти
// Внутри использует массив, не хеш-таблицу
for (Color color : Color.values()) {
String hex = map.get(color);
System.out.println(color + ": " + hex);
}
Характеристики:
- Только для enum ключей
- Очень быстрая (использует массив)
- Экономна по памяти
- Предсказуемый порядок итерации
SortedMap и NavigableMap интерфейсы
// SortedMap — отсортированная Map
SortedMap<String, Integer> sorted = new TreeMap<>();
sorted.put("c", 3);
sorted.put("a", 1);
sorted.put("b", 2);
Set<String> headSet = sorted.headMap("b").keySet(); // {"a"}
Set<String> tailSet = sorted.tailMap("b").keySet(); // {"b", "c"}
// NavigableMap — расширенная SortedMap
NavigableMap<String, Integer> nav = new TreeMap<>();
String floor = nav.floorKey("b"); // Наибольший <= "b"
String ceiling = nav.ceilingKey("b"); // Наименьший >= "b"
String higher = nav.higherKey("b"); // Наименьший > "b"
String lower = nav.lowerKey("b"); // Наибольший < "b"
Сравнительная таблица
| Класс | Упорядочивание | Thread-Safe | Производительность | Null ключ | Null значение |
|---|---|---|---|---|---|
| HashMap | Нет | Нет | O(1) | Да | Да |
| TreeMap | По ключам | Нет | O(log n) | Нет | Да |
| LinkedHashMap | По добавлению | Нет | O(1) | Да | Да |
| ConcurrentHashMap | Нет | Да | O(1) | Нет | Нет |
| Hashtable | Нет | Да | O(1) | Нет | Нет |
| WeakHashMap | Нет | Нет | O(1) | Да | Да |
| IdentityHashMap | Нет | Нет | O(1) | Да | Да |
| EnumMap | По enum | Нет | O(1) | Нет | Да |
Когда использовать какую
// Стандартный случай
Map<String, Integer> map = new HashMap<>();
// Нужна сортировка
Map<String, Integer> sorted = new TreeMap<>();
// Нужна многопоточность
Map<String, Integer> concurrent = new ConcurrentHashMap<>();
// Нужен LRU кэш
Map<String, String> lruCache = new LinkedHashMap<>(16, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > MAX_SIZE;
}
};
// Нужны enum ключи
Map<Status, Integer> statusCounts = new EnumMap<>(Status.class);
// Нужна слабая ссылка
Map<ClassName, Metadata> classCache = new WeakHashMap<>();
Лучшие практики
- HashMap по умолчанию — быстрая и удобная
- TreeMap для сортировки — но медленнее
- ConcurrentHashMap для многопоточности — никогда не используй synchronized HashMap
- LinkedHashMap для LRU — эффективнее собственной реализации
- EnumMap для enum ключей — оптимальна по памяти
- Не используй Hashtable — это история
Выбор правильной реализации Map критичен для производительности приложения.