Understanding Java HashMap: Internal Mechanics of get and put with a Country Example
This article explains Java HashMap internals by walking through a concrete Country‑key example, illustrating how keys are hashed, stored in an internal Entry array, and how the put and get methods handle collisions using linked lists, complemented by full source code snippets.
When interviewing for Java positions, candidates often face questions about how HashMap works internally, especially the get and put operations. This tutorial uses a simple example with a Country class as the key and its capital name as the value to demonstrate the underlying mechanisms.
package org.arpit.javapostsforlearning;
public class Country {
String name;
long population;
public Country(String name, long population) {
super();
this.name = name;
this.population = population;
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public long getPopulation() { return population; }
public void setPopulation(long population) { this.population = population; }
// Simplified hashCode for demonstration: even‑length names return 31, odd‑length names return 95
@Override
public int hashCode() {
if (this.name.length() % 2 == 0)
return 31;
else
return 95;
}
@Override
public boolean equals(Object obj) {
Country other = (Country) obj;
if (name.equalsIgnoreCase(other.name))
return true;
return false;
}
} import java.util.HashMap;
import java.util.Iterator;
public class HashMapStructure {
public static void main(String[] args) {
Country india = new Country("India", 1000);
Country japan = new Country("Japan", 10000);
Country france = new Country("France", 2000);
Country russia = new Country("Russia", 20000);
HashMap<Country, String> countryCapitalMap = new HashMap<>();
countryCapitalMap.put(india, "Delhi");
countryCapitalMap.put(japan, "Tokyo");
countryCapitalMap.put(france, "Paris");
countryCapitalMap.put(russia, "Moscow");
Iterator<Country> countryCapitalIter = countryCapitalMap.keySet().iterator();
while (countryCapitalIter.hasNext()) {
Country countryObj = countryCapitalIter.next();
String capital = countryCapitalMap.get(countryObj);
System.out.println(countryObj.getName() + "----" + capital);
}
}
}Running the program in a debugger and watching the countryCapitalMap reveals an internal table of size 16 that stores Entry objects. Each Entry holds a key, a value, a reference to the next entry (for handling collisions), and the pre‑computed hash.
static class Entry implements Map.Entry {
final K key;
V value;
Entry next;
final int hash;
// ... more fields and methods
}The hash of a key is obtained from its hashCode() method; the map then applies an additional hashing step and uses indexFor(hash, table.length) to locate the bucket (array index). If two keys produce the same hash, they are stored in the same bucket as a linked list.
/**
* Associates the specified value with the specified key in this map.
*/
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}The put method first checks for a null key, computes the hash, finds the bucket, and then scans the linked list at that bucket. If an existing entry with the same key is found (using equals), its value is replaced; otherwise a new Entry is added.
/**
* Returns the value to which the specified key is mapped, or {@code null}.
*/
public V get(Object key) {
if (key == null)
return getForNullKey();
int hash = hash(key.hashCode());
for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
return e.value;
}
return null;
}The get method mirrors the steps of put: null check, hash computation, bucket location, and linked‑list traversal until a matching key is found, at which point the associated value is returned.
Key takeaways:
HashMap stores entries in an internal Entry[] table (buckets).
The bucket index is derived from the key's hashCode() after an additional hashing step.
Collisions are resolved by chaining entries in a linked list within the same bucket.
The equals() method of the key determines logical equality during both put and get.
Values' equals() and hashCode() are not used by the map.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Captain
Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
