This tutorial walks you through creating a custom HashMap in Java. You’ll learn how to implement:
- A hash function
- Basic operations like
put,get, andremove - Collision handling using a custom singly linked list (not
java.util.LinkedList)
We’ll use:
- A fixed-size array of 16 buckets
- Our own
Entryclass to create a linked list structure for each bucket
This version does not include initial capacity, load factor, or resizing to keep it simple and focused.
Step 1: Define the MyHashMap Class and Entry Nodes
public class MyHashMap<K, V> {
private static class Entry<K, V> {
final K key;
V value;
Entry<K, V> next;
Entry(K key, V value) {
this.key = key;
this.value = value;
}
}
private Entry<K, V>[] table;
public MyHashMap() {
table = new Entry[16];
}
}
Detailed Explanation:
- The array
table[16]is the base structure where entries are stored by hash index. - Each element in the array points to the head of a linked list.
- The
Entry<K, V>class stores a key, value, andnextreference. - The
nextreference connects multiple entries in the same bucket, forming a singly linked list. - This is a custom list using nodes; we do not use Java’s
LinkedList.
Step 2: Compute Hash (Array Index)
private int hash(K key) {
return key == null ? 0 : Math.abs(key.hashCode() % table.length);
}
Explanation:
- Converts a key into an index within the array.
- We use
hashCode()and modulo by array length to stay within bounds. Math.abs()ensures a non-negative index.- If the key is
null, we assign it to index0.
Step 3: Insert Key-Value Pair (put method)
public void put(K key, V value) {
int index = hash(key);
Entry<K, V> head = table[index];
while (head != null) {
if ((key == null && head.key == null) || (key != null && key.equals(head.key))) {
head.value = value;
return;
}
head = head.next;
}
Entry<K, V> newEntry = new Entry<>(key, value);
newEntry.next = table[index];
table[index] = newEntry;
}
Explanation:
- Computes the index using the hash function.
- Checks for existing key in the bucket’s linked list.
- If found, updates the value.
- If not, inserts a new node at the beginning of the linked list.
- The
nextpointer handles chaining:newEntry.next = table[index].
Step 4: Retrieve Value by Key (get method)
public V get(K key) {
int index = hash(key);
Entry<K, V> head = table[index];
while (head != null) {
if ((key == null && head.key == null) || (key != null && key.equals(head.key))) {
return head.value;
}
head = head.next;
}
return null;
}
Explanation:
- Finds the correct bucket using the hash function.
- Walks through the linked list at that index.
- If the key is found, returns its value.
- If the key is not found, returns
null.
Step 5: Remove Key-Value Pair (remove method)
public V remove(K key) {
int index = hash(key);
Entry<K, V> current = table[index];
Entry<K, V> previous = null;
while (current != null) {
if ((key == null && current.key == null) || (key != null && key.equals(current.key))) {
if (previous == null) {
table[index] = current.next;
} else {
previous.next = current.next;
}
return current.value;
}
previous = current;
current = current.next;
}
return null;
}
Explanation:
- Uses the hash to locate the correct bucket.
- Walks through the linked list to find the matching key.
- If the key is found, removes the corresponding node.
- Adjusts the
nextpointer to maintain the linked structure. - Returns the removed value, or
nullif not found.
Step 6: Test the HashMap
public class Main {
public static void main(String[] args) {
MyHashMap<String, String> map = new MyHashMap<>();
map.put("name", "Alice");
map.put("city", "Mumbai");
map.put("language", "Java");
System.out.println("name -> " + map.get("name"));
System.out.println("city -> " + map.get("city"));
System.out.println("language -> " + map.get("language"));
map.remove("city");
System.out.println("city -> " + map.get("city"));
}
}
How Buckets Work Internally
If multiple keys hash to the same index (for example, index 3), the internal structure looks like this:
table[3] → [A, valueA] → [B, valueB] → [C, valueC] → null
- Each element in the array is a pointer to the head of a linked list.
- Each
[key, value]pair is anEntryobject. - The
nextfield links the entries in the same bucket.
