home / java / hashmap-internal-working-in-java-what-happens-when-you-execute-map-putjava-100
Java

HashMap Internal Working in Java: What Happens When You Execute map.put(“Java”, 100)?

HashMap is one of the most frequently asked topics in Java interviews. Almost every interviewer asks:

“Can you explain what happens internally when we execute map.put("Java", 100)?”

Understanding the internal working of HashMap will help you answer confidently in interviews and write better Java code.

Let’s understand each step in detail.


Example

HashMap<String, Integer> map = new HashMap<>();

map.put("Java", 100);

When the put() method is called, HashMap performs the following operations internally.


Step 1: Calculate the Hash

The first thing HashMap does is calculate the hash value of the key.

"Java".hashCode();

For a String, Java computes a unique integer hash code based on the characters in the string.

For example:

"Java".hashCode() = 2301506

(Actual value isn’t important; it’s just an integer.)

Instead of using the hash directly, HashMap applies an additional bit-mixing operation to distribute keys more evenly.

Internally, Java performs something similar to:

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

Why is bit mixing needed?

Without bit mixing, many keys could end up in the same bucket, increasing collisions.

Bit mixing improves the distribution of keys across buckets, resulting in faster lookups.


Step 2: Find the Bucket Index

Once the hash is calculated, HashMap determines where the entry should be stored.

It calculates the bucket index using:

index = (n - 1) & hash;

where:

  • n = current table size (capacity)
  • hash = hash value calculated in Step 1

Suppose the table size is:

Capacity = 16

Then:

index = (16 - 1) & hash

The calculated index might be:

Bucket = 5

So HashMap now knows that the key should be stored in Bucket 5.


Step 3: Check the Bucket

Now HashMap checks whether the bucket is empty.

Suppose the bucket looks like this:

Bucket 5

Empty

Since nothing exists there, HashMap creates a new node.

Internally, something similar to this happens:

new Node(hash, "Java", 100, null)

The bucket now becomes:

Bucket 5

[Java,100]

The insertion is complete.


What if the Bucket is Already Occupied?

Now consider another insertion:

map.put("Python", 200);

Assume "Python" also maps to Bucket 5.

The bucket already contains:

Bucket 5

[Java,100]

Since the bucket is not empty, HashMap cannot directly insert the new node.

Instead, it compares the keys.

Internally:

existingKey.equals(newKey)

becomes

"Java".equals("Python")

Result:

false

The keys are different, so this is a collision.


Step 4: Handle Collision

A collision occurs when two different keys map to the same bucket.

There are two possible cases.


Case 1: Same Key → Update the Value

Suppose you execute:

map.put("Java", 300);

The bucket contains:

[Java,100]

HashMap compares:

"Java".equals("Java")

Result:

true

Since the key already exists, HashMap does not create a new node.

Instead, it updates the existing value.

Before:

[Java,100]

After:

[Java,300]

The old value (100) is replaced by the new value (300).


Case 2: Different Key → Create a New Node

Now consider:

map.put("Python", 200);

The bucket already contains:

[Java,100]

Comparison:

"Java".equals("Python")

Result:

false

Since the keys are different, HashMap creates a new node and links it to the existing one.

Bucket 5

[Java,100]
      |
      v
[Python,200]

This linked structure is how HashMap handles collisions.


What Happens if Many Keys Collide?

Suppose many keys map to the same bucket.

Bucket 5

Java
  |
Python
  |
Spring
  |
Hibernate
  |
Docker
  |
Kubernetes

Searching through a long linked list becomes slow.

Before Java 8, buckets always remained linked lists.

Starting with Java 8, if:

  • Bucket size becomes greater than or equal to 8, and
  • Table capacity is at least 64

then the linked list is converted into a Red-Black Tree.

          Java
         /    \
    Docker   Python
      /          \
 Spring      Kubernetes

A Red-Black Tree reduces search complexity from:

O(n)

to

O(log n)

making lookups much faster when many collisions occur.


Step 5: Check the Load Factor

After inserting the new node, HashMap checks whether resizing is required.

By default:

Capacity = 16
Load Factor = 0.75

Threshold:

16 × 0.75 = 12

This means the table can hold 12 entries before resizing.

When the 13th entry is inserted:

size = 13

Since:

13 > 12

HashMap resizes the table.

Old Capacity = 16
New Capacity = 32

After resizing, every existing entry is recalculated and placed into its new bucket.

This process is called rehashing.


Complete Flow of put()

map.put("Java",100)

        |
        v
Calculate hash
        |
        v
Find bucket index
        |
        v
Is bucket empty?
     /          \
   Yes          No
    |            |
Create Node   Compare keys
    |            |
Store Node   equals() ?
               /      \
            true      false
             |          |
       Update value   Add new Node
                         |
                         v
                 Linked List / Tree
                         |
                         v
                Check Load Factor
                         |
                         v
               Resize if threshold exceeded

Time Complexity

OperationAverageWorst Case
put()O(1)O(n)
get()O(1)O(n)
remove()O(1)O(n)

With treeification (Java 8+), the worst-case lookup in a heavily-collided bucket improves to O(log n).


Interview Answer (30 Seconds)

When map.put("Java", 100) is executed, HashMap first calculates the hash of the key and applies bit mixing. It then computes the bucket index using (n - 1) & hash. If the bucket is empty, it creates a new node and stores it. If the bucket already contains entries, it compares keys using equals(). If the key matches, it updates the existing value; otherwise, it adds a new node to the bucket. If too many collisions occur, the linked list is converted into a Red-Black Tree in Java 8+. Finally, if the number of entries exceeds capacity × loadFactor (default 0.75), the table is resized and all entries are rehashed.