Skip to content

Commit 14f570b

Browse files
committed
How Data Is Stored Internally In HashMap
Signed-off-by: https://github.com/Someshdiwan <[email protected]>
1 parent 30b1e0a commit 14f570b

File tree

9 files changed

+373
-0
lines changed

9 files changed

+373
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
hashCode → bucketIndex mapping in HashMap:
2+
3+
4+
5+
1. Formula Recap
6+
7+
HashMap internally hashCode ko le kar bucket index nikalta hai:
8+
9+
bucketIndex = (hashCode(key)) & (n - 1)
10+
11+
• n = array ka size (capacity), always power of 2 (like 16, 32, …).
12+
• & (n-1) fast modulus operation hai (better than %).
13+
14+
15+
16+
2. Example Keys
17+
• Key1 = "ABC" → hashCode = 64578
18+
• Key2 = "CBA" → hashCode = 64018
19+
20+
Assume HashMap ki capacity = 16 (default).
21+
22+
23+
24+
3. Calculate Bucket Index
25+
26+
bucketIndex("ABC") = 64578 & (16 - 1)
27+
= 64578 & 15
28+
= 2
29+
30+
bucketIndex("CBA") = 64018 & (16 - 1)
31+
= 64018 & 15
32+
= 2
33+
34+
Dono ka bucket index 2 nikla → Collision!
35+
36+
37+
38+
4. ASCII Diagram: Buckets in HashMap
39+
40+
HashMap Buckets (capacity = 16)
41+
42+
Index: 0 1 2 3 4 ... 15
43+
─────────────────────────────────
44+
Bucket: [ ] [ ] [ "ABC" ] [ ] [ ] [ ]
45+
46+
After inserting "CBA":
47+
48+
Index: 0 1 2 3 4 ... 15
49+
──────────────────────────────────────
50+
Bucket: [ ] [ ] [ "ABC" -> "CBA" ] [ ] [ ] [ ]
51+
52+
53+
54+
5. How Collision is Handled?
55+
• Java 7 and earlier → LinkedList chaining (all collided entries chained at same bucket).
56+
• Java 8+ → If too many collisions (≥ 8 entries in one bucket),
57+
LinkedList is converted into a Balanced Tree (Red-Black Tree) for faster lookup (O(log n)).
58+
59+
60+
61+
HashMap me hashCode → bucketIndex mapping karke decide hota hai key kis bucket me jayega.
62+
63+
Agar same bucketIndex nikla → collision → LinkedList ya Tree structure use hota hai.
64+
65+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
How HashMap Uses hashCode() and equals()
2+
3+
A HashMap in Java stores key-value pairs.
4+
5+
When inserting an object as a key, HashMap:
6+
- Computes its hashCode() to determine the bucket index.
7+
- Uses equals() to check if two objects are identical.
8+
9+
---
10+
11+
What Are We Doing Here?
12+
13+
We are demonstrating how HashMap works internally when we use custom objects (Person) as keys.
14+
15+
Specifically, we are implementing the hashCode() and equals() methods to ensure proper behavior when storing and
16+
retrieving values from a HashMap.
17+
18+
---
19+
20+
Key Concepts Demonstrated in the Code
21+
-------------------------------------
22+
23+
1. Using HashMap with a Custom Class (Person) as Key
24+
- `HashMap<Person, String> map = new HashMap<>();`
25+
- We store a person's profession (e.g., "Engineer") using Person objects as keys.
26+
27+
2. How hashCode() and equals() Work in HashMap
28+
- `hashCode()` ensures that objects with the same name and id have the same hash code.
29+
- `equals()` ensures that if two Person objects have the same name and id, they are treated as the same key.
30+
31+
3. How Entries are Stored in HashMap
32+
- `map.put(p1, "Engineer");` → p1 (Alice, 1) is stored.
33+
- `map.put(p2, "Designer");` → p2 (Bob, 2) is stored.
34+
- `map.put(p3, "Manager");` → p3 (Alice, 1) has the same hash code as p1, so it replaces p1's value.
35+
36+
4. Checking HashMap Behavior
37+
38+
System.out.println(“HashMap Size: “ + map.size()); // Output: 2
39+
System.out.println(“Value for p1: “ + map.get(p1)); // Output: Manager
40+
System.out.println(“Value for p3: “ + map.get(p3)); // Output: Manager
41+
42+
- Even though we inserted three objects, the size is 2 because p3 replaced p1.
43+
44+
5. Comparing with a HashMap<String, Integer>
45+
46+
Map<String, Integer> map1 = new HashMap<>();
47+
map1.put(“Shubham”, 90);
48+
map1.put(“Neha”, 92);
49+
map1.put(“Shubham”, 99);
50+
51+
// Shubham is added twice, but its value (90) is replaced with (99).
52+
53+
- HashMap maintains unique keys, and if a duplicate key is added, it replaces the existing value.
54+
55+
---
56+
57+
Internal Working of HashMap
58+
---------------------------
59+
60+
Step 1: Calculate hashCode()
61+
62+
@Override
63+
public int hashCode() {
64+
return Objects.hash(name, id);
65+
}
66+
67+
- Generates a hash code based on `name` and `id`.
68+
69+
Step 2: Determine Bucket Index
70+
- The hash code is used to determine the bucket.
71+
- If two objects have the same hash code, they go into the same bucket.
72+
73+
Step 3: Handle Collisions Using equals()
74+
75+
@Override
76+
public boolean equals(Object obj) {
77+
if (this == obj) return true;
78+
if (obj == null || getClass() != obj.getClass()) return false;
79+
Person other = (Person) obj;
80+
return id == other.id && Objects.equals(name, other.name);
81+
}
82+
83+
- If `equals()` returns true, the new value replaces the old value.
84+
85+
---
86+
87+
Code Example
88+
------------
89+
```java
90+
import java.util.*;
91+
92+
class Person {
93+
private String name;
94+
private int id;
95+
96+
public Person(String name, int id) {
97+
this.name = name;
98+
this.id = id;
99+
}
100+
101+
@Override
102+
public int hashCode() {
103+
return Objects.hash(name, id);
104+
}
105+
106+
@Override
107+
public boolean equals(Object obj) {
108+
if (this == obj) return true;
109+
if (obj == null || getClass() != obj.getClass()) return false;
110+
Person other = (Person) obj;
111+
return id == other.id && Objects.equals(name, other.name);
112+
}
113+
}
114+
115+
public class HashMapDemo {
116+
public static void main(String[] args) {
117+
Map<Person, String> map = new HashMap<>();
118+
119+
Person p1 = new Person("Alice", 1);
120+
Person p2 = new Person("Bob", 2);
121+
Person p3 = new Person("Alice", 1);
122+
123+
map.put(p1, "Engineer");
124+
map.put(p2, "Designer");
125+
map.put(p3, "Manager");
126+
127+
System.out.println("HashMap Size: " + map.size());
128+
System.out.println("Value for p1: " + map.get(p1));
129+
System.out.println("Value for p3: " + map.get(p3));
130+
}
131+
}
132+
133+
134+
135+
Conclusion
136+
1. Without hashCode() and equals(), HashMap would treat all Person objects as unique, even if they had the same name and id.
137+
2. Implementing hashCode() and equals() ensures correct key comparison and prevents duplicate keys.
138+
3. This behavior is similar to how HashMap<String, Integer> works, where the same string key replaces the previous value.
139+
140+
---
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
code + diagram showing, how p1 and p3 (same hash, same equals) land in the same bucket, and why one replaces the other:
2+
3+
How HashMap Uses hashCode() and equals():
4+
5+
A HashMap in Java stores key-value pairs.
6+
7+
When inserting an object as a key, HashMap:
8+
- Computes its hashCode() to determine the bucket index.
9+
- Uses equals() to check if two objects are identical.
10+
11+
---
12+
13+
Key Concepts with Example (Person class)
14+
----------------------------------------
15+
16+
1. Custom Object as Key
17+
- We create a `Person` class with `name` and `id`.
18+
- Implement `hashCode()` and `equals()` so HashMap can identify duplicates.
19+
20+
2. Behavior
21+
- `map.put(p1, "Engineer");` → p1 (Alice, 1) stored.
22+
- `map.put(p2, "Designer");` → p2 (Bob, 2) stored.
23+
- `map.put(p3, "Manager");` → p3 (Alice, 1) same hash + equals → replaces p1’s value.
24+
25+
3. Result
26+
- `map.size()` → 2 (because p3 replaced p1).
27+
- `map.get(p1)` and `map.get(p3)` → both return `"Manager"`.
28+
29+
---
30+
31+
Code Example
32+
33+
import java.util.*;
34+
35+
class Person {
36+
private String name;
37+
private int id;
38+
39+
public Person(String name, int id) {
40+
this.name = name;
41+
this.id = id;
42+
}
43+
44+
@Override
45+
public int hashCode() {
46+
return Objects.hash(name, id); // Hash based on name + id
47+
}
48+
49+
@Override
50+
public boolean equals(Object obj) {
51+
if (this == obj) return true;
52+
if (obj == null || getClass() != obj.getClass()) return false;
53+
Person other = (Person) obj;
54+
return id == other.id && Objects.equals(name, other.name);
55+
}
56+
}
57+
58+
public class HashMapDemo {
59+
public static void main(String[] args) {
60+
Map<Person, String> map = new HashMap<>();
61+
62+
Person p1 = new Person("Alice", 1);
63+
Person p2 = new Person("Bob", 2);
64+
Person p3 = new Person("Alice", 1); // Same as p1 logically
65+
66+
map.put(p1, "Engineer");
67+
map.put(p2, "Designer");
68+
map.put(p3, "Manager"); // Replaces value of p1
69+
70+
System.out.println("HashMap Size: " + map.size());
71+
System.out.println("Value for p1: " + map.get(p1));
72+
System.out.println("Value for p3: " + map.get(p3));
73+
}
74+
}
75+
76+
77+
78+
ASCII Diagram — How Keys Are Stored
79+
80+
Assume capacity = 4 buckets for simplicity.
81+
82+
Buckets: index 0 1 2 3
83+
| | | |
84+
v v v v
85+
[ ] [p2] [p1] [ ]
86+
87+
Step 1: p1 ("Alice",1) hashes → bucket[2]
88+
bucket[2] -> (Alice,1,"Engineer")
89+
90+
Step 2: p2 ("Bob",2) hashes → bucket[1]
91+
bucket[1] -> (Bob,2,"Designer")
92+
93+
Step 3: p3 ("Alice",1) hashes → bucket[2]
94+
- Same hash as p1
95+
- equals() → true
96+
- REPLACE old value
97+
98+
Final State:
99+
bucket[1] -> (Bob,2,"Designer")
100+
bucket[2] -> (Alice,1,"Manager")
101+
102+
103+
104+
Conclusion
105+
1. hashCode() decides the bucket (fast lookup).
106+
2. equals() decides whether to overwrite or treat as a new entry.
107+
3. That’s why p3 replaces p1, keeping HashMap keys unique.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
ASCII Diagram — How HashMap Stores Keys and Values (Buckets):
2+
3+
This simplified ASCII shows how HashMap maps keys to buckets using hashCode → index, and how collisions are chained
4+
(linked list or tree after a threshold).
5+
6+
Assume capacity = 8 (bucket array of size 8).
7+
Index is computed from hash(key).
8+
9+
Buckets (index 0..7):
10+
11+
index: 0 1 2 3 4 5 6 7
12+
| | | | | | | |
13+
v v v v v v v v
14+
[ ] [K2] [K1] [ ] [K3] [ ] [K4] -> [K5] [ ]
15+
16+
Legend:
17+
- [Kx] denotes a node storing (key, value, hash, next)
18+
- "->" denotes chaining (collision list).
19+
- After Java 8, long chains may convert into a balanced tree (for performance).
20+
21+
------------------------------------------------------------
22+
23+
Example Mapping (Conceptual):
24+
- Key K1 hashes to index 2 → bucket[2] → (K1, V1)
25+
- Key K2 hashes to index 1 → bucket[1] → (K2, V2)
26+
- Key K3 hashes to index 4 → bucket[4] → (K3, V3)
27+
- Key K4 and K5 both hash to index 6 (collision):
28+
bucket[6] → (K4, V4) → (K5, V5)
29+
If depth > TREEIFY_THRESHOLD, this bucket may become a Red-Black Tree.
30+
31+
------------------------------------------------------------
32+
33+
Memory Layout (Simplified):
34+
- table[] → array of Node<K,V> references (size = capacity).
35+
- Each Node contains: int hash; K key; V value; Node<K,V> next;
36+
37+
------------------------------------------------------------
38+
39+
How get(key) Works (High Level):
40+
1. Compute hash = spread(key.hashCode()).
41+
2. index = (table.length - 1) & hash // fast modulus since length is power of 2.
42+
3. node = table[index]
43+
4. while (node != null):
44+
if (node.hash == hash && node.key.equals(key)) return node.value
45+
node = node.next
46+
5. If not found → return null.
47+
48+
------------------------------------------------------------
49+
50+
Rehashing (Resize) Steps (when size > threshold):
51+
1. Create new table with larger capacity (usually double).
52+
2. Recompute index for each existing node.
53+
3. Move nodes to new table.
54+
4. Update reference to new table.
55+
56+
------------------------------------------------------------
57+
58+
Notes:
59+
- Good hashCode() distribution avoids collisions.
60+
- Default capacity = 16, load factor = 0.75 → threshold = 16 * 0.75 = 12
61+
- HashMap allows one null key (stored in table[0]) and multiple null values.

0 commit comments

Comments
 (0)