HashMap in Java Explained – Internal Working, Evolution & Real Insights

HashMap Internals | Code2java

πŸ”₯ Table of Contents

  • Introduction to HashMap
  • Why Do We Need HashMap
  • Internal Working of HashMap
  • Java 8 Enhancements in HashMap
  • Practical Implementation in Java
  • Summary
  • Interview Questions

Introduction to HashMap

HashMap is one of the most commonly used data structures in Java from the java.util package.

πŸ‘‰ It stores data in key-value pairs
πŸ‘‰ It allows null key (only one) and multiple null values
πŸ‘‰ It is NOT thread-safe
πŸ‘‰ It provides constant time performance O(1) for basic operations (get/put)

Example:

import java.util.HashMap;

public class Example {
    public static void main(String[] args) {
        HashMap<Integer, String> map = new HashMap<>();
        
        map.put(1, "Java");
        map.put(2, "Python");
        map.put(3, "C++");

        System.out.println(map.get(2)); // Python
    }
}

Why Do We Need HashMap

Imagine you need:

πŸ‘‰ Fast lookup by key
πŸ‘‰ Unique keys
πŸ‘‰ Efficient insertions

HashMap solves all of these efficiently.

Without HashMap:

  • Searching in a list β†’ O(n)

With HashMap:

  • Searching β†’ O(1) average case βœ…

πŸ’‘ Real-world usage:

  • Caching
  • Database indexing
  • Counting frequency of elements

Internal Working of HashMap

Let’s break this down step by step.

Hashing Mechanism

πŸ‘‰ When you insert a key:

map.put("apple", 10);

Java does:

πŸ‘‰ Calls hashCode() on key
πŸ‘‰ Converts it into a hash
πŸ‘‰ Maps it to an index in array

Formula:

πŸ‘‰ index = hash & (n – 1)

Where n = capacity of array

Internal Data Structure

HashMap internally uses:

πŸ‘‰ Array of Nodes (buckets)

Each bucket contains:

static class Node<K,V> {
    final int hash;
    final K key;
    V value;
    Node<K,V> next;
}

πŸ‘‰ Each bucket acts like a LinkedList (before Java 8)

Collision Handling

πŸ”₯ Collision happens when:

Two keys produce same index

Example:

map.put("FB", 1);
map.put("Ea", 2);

These two strings produce same hashCode!

πŸ‘‰ Then they are stored in same bucket using LinkedList

Structure:

Bucket β†’ [Node1] β†’ [Node2] β†’ [Node3]

⚠️ Problem:
Too many collisions β†’ performance becomes O(n)

Retrieval Process

map.get("apple");

Steps:

πŸ‘‰ Calculate hash
πŸ‘‰ Find bucket index
πŸ‘‰ Traverse linked list
πŸ‘‰ Compare keys using equals()

πŸ‘‰ Return value if match found

Resizing and Rehashing

πŸ”₯ Default capacity = 16
πŸ”₯ Load factor = 0.75

When size exceeds:

πŸ‘‰ capacity * loadFactor (16 * 0.75 = 12)

Then:

πŸ‘‰ Array size doubles (16 β†’ 32)
πŸ‘‰ All entries are rehashed

⚠️ Rehashing is expensive operation

Java 8 Enhancements in HashMap

Java 8 brought a major optimization πŸ”₯

Treeification (LinkedList β†’ Red-Black Tree)

When number of nodes in a bucket exceeds 8:

πŸ‘‰ LinkedList β†’ Red-Black Tree

Condition:

πŸ‘‰ bucket size β‰₯ 8 AND capacity β‰₯ 64

Performance Improvement

πŸ‘‰ LinkedList search = O(n)
πŸ‘‰ Tree search = O(log n) βœ…

This significantly improves worst-case performance.

Untreeification

If nodes drop below 6:

πŸ‘‰ Tree β†’ LinkedList again

Improved Hashing Technique

Java 8 improves hash distribution:

hash = key.hashCode() ^ (hash >>> 16);

πŸ‘‰ This reduces collisions

Practical Implementation in Java

Let’s simulate collision and understand behavior.

import java.util.HashMap;

class Key {
    String value;

    Key(String value) {
        this.value = value;
    }

    @Override
    public int hashCode() {
        return 1; // Force collision
    }

    @Override
    public boolean equals(Object obj) {
        return this.value.equals(((Key) obj).value);
    }
}

public class HashMapInternalDemo {
    public static void main(String[] args) {
        HashMap<Key, String> map = new HashMap<>();

        map.put(new Key("A"), "Apple");
        map.put(new Key("B"), "Ball");
        map.put(new Key("C"), "Cat");

        System.out.println(map);
    }
}

πŸ‘‰ All keys go into same bucket due to same hashCode

πŸ’‘ This helps visualize collision handling

Important Internal Methods

Some key internal methods:

πŸ‘‰ putVal() β†’ handles insertion
πŸ‘‰ resize() β†’ handles rehashing
πŸ‘‰ treeifyBin() β†’ converts list to tree
πŸ‘‰ getNode() β†’ retrieves value

Summary

βœ… HashMap uses array + hashing
βœ… Collisions handled using LinkedList (Java 7)
βœ… Java 8 uses Red-Black Tree for optimization
βœ… Average complexity β†’ O(1)
βœ… Worst case improved from O(n) β†’ O(log n)

πŸ’‘ Key takeaway:
Good hashCode() implementation is critical for performance

Interview Questions

  1. What is HashMap and how does it work internally?
    πŸ‘‰ It uses hashing and array of buckets to store key-value pairs.
  2. What is collision in HashMap?
    πŸ‘‰ When multiple keys map to same bucket index.
  3. How does Java 8 improve HashMap performance?
    πŸ‘‰ Converts LinkedList into Red-Black Tree after threshold.
  4. What is load factor?
    πŸ‘‰ It defines when resizing should happen (default 0.75).
  5. Why hashCode() and equals() both are required?
    πŸ‘‰ hashCode() finds bucket, equals() finds exact key.
  6. What is treeification threshold?
    πŸ‘‰ 8 nodes in a bucket.
  7. Is HashMap thread-safe?
    πŸ‘‰ No.
  8. What happens during rehashing?
    πŸ‘‰ Capacity doubles and all entries are redistributed.

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top