In Java, String is the most widely used key type in a HashMap. But how does Java treat a string defined as a raw literal (e.g., "A") compared to a string allocated dynamically in memory using the new keyword (e.g., new String("A"))? Do they act as the same key or separate keys?
In this guide, we will answer these questions using a key-maker analogy and walk through a step-by-step trace of Java's String pool lookup behavior.
Imagine a bank vault with a **treasure box** inside. To open the box, you must present a key with the letter "A" engraved on it.
Two customers arrive wanting to open the treasure box using two different key sources:
- Customer 1 (String Literal): Takes a key engraved with "A" from the hotel's common key-rack (the **String Pool**). This rack stores unique keys so we don't have to waste time carving new ones. This key is labeled
str. - Customer 2 (New String): Decides to ignore the common key-rack. They buy a fresh block of metal and carve their own key engraved with "A" using a copy-machine (the **heap memory**). This key is labeled
str1.
When the bank guard compares the keys, they do not care about where the keys were manufactured (whether they point to the key-rack or the heap). They only look at the **engraving** on the key (using equals()). Since both keys are engraved with "A", they are deemed identical, and both open the exact same treasure box!
Walkthrough of the Main Method Scenario
Let's trace how the program executes step-by-step from the entry point of the main method:
The program declares two string variables in different memory areas:
String str = "A";
String str1 = new String("A");
strpoints directly to the string literal"A"cached inside Java's String Constant Pool.str1points to a new String instance allocated inside the Heap memory, which internally wraps the character array{'A'}.- If you compared them using reference equality (
str == str1), it would evaluate tofalsebecause they point to different memory addresses.
The program creates a HashMap and registers the first key:
Map<String, Integer> map = new HashMap<>();
map.put(str, 10);
The map evaluates `str.hashCode()`, determines the bucket location, and inserts the pair: {"A" -> 10}. The map size is now 1.
Now, the program attempts to register the heap-allocated key:
map.put(str1, 20);
HashMap does its checks:
- It evaluates `str1.hashCode()`. Since `hashCode()` in the String class is computed strictly based on the character values, it returns the exact same integer hash code as `str`.
- The map goes to the same bucket and finds the entry for `str` ("A").
- It calls
str1.equals(str). The String class overrides the `equals` method to compare the character sequences. Since both represent"A", the comparison returnstrue. - The map concludes the key already exists and **overwrites** the value with 20.
When the program executes System.out.println(map.size()), it prints 1. The heap-allocated key did not create a new map entry.
Java Implementation
Below is the complete Java code demonstrating how different String instances representing the same text collapse to a single key in a HashMap:
package io.practise.accolite;
import java.util.HashMap;
import java.util.Map;
public class StringInMap {
public static void main(String[] args) {
String str = "A";
String str1 = new String("A");
Map<String, Integer> map = new HashMap<>();
map.put(str, 10);
map.put(str1, 20);
System.out.println(map.size());
}
}
Conclusion
Java's HashMap uses content equality (equals()) rather than reference equality (==) to resolve keys. Because the String class implements content equality, any two string objects with the same sequence of letters will resolve to the same key, regardless of whether they reside in the String Constant Pool or as separate objects on the Heap.