Ответ
HashMap хранит пары ключ-значение в "корзинах" (buckets) на основе хэш-кода ключа. При добавлении элемента:
- Вычисляется хэш ключа через
hashCode() - По хэшу определяется индекс корзины:
index = hash & (capacity - 1) - Если корзина пуста - элемент добавляется
- При коллизии (одинаковый хэш) используется цепочка (в Java 8 при длине >8 переходит на красно-черное дерево)
Пример:
HashMap<String, Integer> map = new HashMap<>();
map.put("apple", 1); // hash("apple") -> индекс корзины
map.get("apple"); // быстрый доступ по хэшу
Особенности:
- Не гарантирует порядок
- Разрешает один null-ключ
- Потоконебезопасен (используйте ConcurrentHashMap)
- Начальная емкость 16, load factor 0.75 (автоматическое расширение)
Ответ 18+ 🔞
Э, слушай, вот объясняю на пальцах, как эта штука работает, а то у некоторых от слова "хэш-таблица" уже волнение ебать начинается.
Представь себе этажерку с ящиками, ёпта. Это и есть наш HashMap. Каждый ящик — это "корзина". Когда ты пытаешься что-то туда засунуть, например, пару "яблоко" -> 1, происходит магия, но не сложная.
Сначала HashMap смотрит на ключ ("яблоко") и орет ему: "А ну-ка, дай свой хэш-код, сука!" (hashCode()). Получает какую-то цифру. Потом он берет эту цифру и быстренько вычисляет, в какой именно ящик на этажерке это дело положить. Формула простая: индекс = хэш & (размер_этажерки - 1). Это как взять последние биты номера — и готово, ящик найден.
Дальше три варианта:
- Ящик пустой — ура, кладём нашу пару и идём пить чай. Всё быстро.
- В ящике уже что-то лежит, но с таким же хэшем (коллизия, блядь!). Тогда
HashMapне паникует. Он просто цепляет новую запись в конец цепочки внутри этого ящика (связный список). Как будто вешает на один крючок вторую куртку. - А вот если в одном ящике скопилось овердохуища записей (больше 8, если быть точным), Java говорит: "Ну нахуй этот список, слишком долго искать". И превращает эту кучу внутри ящика в красно-черное дерево. Это как отсортировать вещи в шкафу — искать быстрее.
Вот пример кода, тут всё просто:
HashMap<String, Integer> map = new HashMap<>();
map.put("apple", 1); // Вычислили хэш от "apple", нашли ящик, положили.
map.get("apple"); // Снова вычислили хэш, моментально нашли тот же ящик, достали значение. Скорость — пизда рулю.
А теперь держи подводные грабли, на которые все наступают:
- Порядок? Не, не слышал. Может выдать элементы в каком угодно порядке, хоть завтра, хоть сегодня. Не гарантирует нихуя.
null-ключ? Да, пожалуйста, один можно. Положи его на особую полочку.- Потоки? Абсолютно потокоНЕбезопасен. Если из двадцати потоков начать в него писать, будет не расширение, а хиросима и нигерсраки. Нужна потокобезопасность — бери
ConcurrentHashMap, не выёбывайся. - Размер? Создаёшь — по умолчанию даёт 16 ящиков (емкость). И есть "коэффициент заполнения" (load factor) — 0.75. Это значит, как только заполнено 75% ящиков (12 из 16), этажерка говорит: "Всё, я хуйня, меня мало!" — и автоматически увеличивает себя вдвое (до 32), перераспределяя все записи по новым ящикам. Операция дорогая, поэтому если знаешь, что будет много данных, задай начальную емкость сразу.
Короче, штука мощная и быстрая, но знать её нюансы надо, а то подозрение ебать чувствую, что многие тыкают в неё, не глядя.
Видео-ответы
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶