If Two Objects Have the Same hashCode(), Are They Necessarily Equal by equals()?
HashMap handles collisions — it stores multiple elements in one bucket and distinguishes them via equals().
🟢 Junior Level
No! Two objects with the same hashCode() are not necessarily equal by equals(). This is called a collision — and it’s a normal situation.
Simple analogy: Two people may live in the same building entrance (same “hash”), but they are different people (not equal by “equals”).
Classic example:
System.out.println("Aa".hashCode()); // 2112
System.out.println("BB".hashCode()); // 2112
System.out.println("Aa".equals("BB")); // false — different strings!
HashMap handles collisions — it stores multiple elements in one bucket and distinguishes them via equals().
🟡 Middle Level
Why Collisions Are Inevitable
hashCode() returns an int — 32 bits, ~4.3 billion values. But there can be more unique objects than fit in JVM memory. Even strings of up to 10 characters: 26^10 = 141 trillion combinations. By the pigeonhole principle, collisions are inevitable.
Two-Stage Filter in HashMap
| Step | Method | Purpose |
|---|---|---|
| 1. Coarse filter | hashCode() |
Determines bucket, filters out 99.9% |
| 2. Precise check | equals() |
Finds specific key in the bucket |
Why HashMap is faster: the two-stage filter is unique to hash collections. In ArrayList, search is linear equals() for EVERY element (O(n)). In TreeMap — compareTo() for each node (O(log n)). In HashMap — hashCode first discards 99.9% of candidates, and equals() is called on only 1-2 elements.
Performance:
- Different hashCode →
equals()not called (fast) - Same hashCode →
equals()called (slower, but precise)
Why hashCode Uniqueness Matters
If all keys have the same hashCode:
- All elements in one bucket
- HashMap degrades to O(n) (list) or O(log n) (tree)
- System becomes vulnerable to DoS attacks
Practical Collision Examples
// Strings
"Aa".hashCode() == "BB".hashCode() // 2112
// Real collision:
new Long(1).hashCode() == 1
new Long(4294967297L).hashCode() == 1 // Same hashCode!
// Bad hashCode
class BadKey {
@Override public int hashCode() { return 1; } // ALWAYS 1!
}
🔴 Senior Level
Collision Mathematics
Birthday Paradox
Birthday paradox: in a group of 23 people, the probability of shared birthdays > 50%. Similarly in HashMap: even with 5 elements and 16 buckets, collision probability > 50%. This is counter-intuitive, but statistically proven.
Performance Impact
| Scenario | Average Chain Length | Complexity |
|---|---|---|
| Good hashCode | 1-2 | O(1) |
| Medium hashCode | 3-5 | O(1) (with large constant) |
| Bad hashCode (constant) | n | O(n) or O(log n) |
Hash Flooding Attack
Attacker crafts keys with the same hash:
- Java 7: 100% CPU on insertion (O(n²))
- Java 8+: mitigated via treeification (O(n log n)), but overhead remains
Internal Mechanics: Treeification on Collisions
At 8+ elements in one bucket and capacity >= 64:
// If keys implement Comparable — compareTo() is used
// If not — tieBreakOrder() via System.identityHashCode()
Implementing Comparable for keys speeds up treeification.
Edge Cases
- All hashCode = 1: In Java 7 — fatal degradation. In Java 8+ — tree, but huge overhead
- hashCode depends on mutable fields: after key modification, hash changes, element is “lost”
- System hashCode:
System.identityHashCode()may coincide for different objects (it’s not a UUID)
Best Practices
- Minimize collisions through quality
hashCode() - Use prime numbers (31, 37, 41) as multipliers
- Include all significant fields from
equals()inhashCode() - For production: monitor hashCode distribution via unit tests
🎯 Interview Cheat Sheet
Must know:
- NO: same hashCode ≠ equal objects — this is called a collision
- Classic example: “Aa” and “BB” both give 2112, but “Aa”.equals(“BB”) = false
- HashMap uses a two-stage filter: hashCode (coarse filter) → equals (precise check)
- Birthday paradox: with 23 elements and 365 buckets, collision probability > 50%
- 2^32 (~4.3 billion) int values don’t cover the infinite set of possible objects
- Bad hashCode (constant) = all elements in one bucket = degradation to O(n)
Common follow-up questions:
- Why are collisions inevitable? — pigeonhole principle: infinite set → finite int range
- How does HashMap distinguish elements in the same bucket? — via equals() along the chain/tree
- What is a Hash Flooding Attack? — attacker generates keys with the same hashCode → DoS
- Can collisions be completely avoided? — no, only minimized with quality hashCode
Red flags (DO NOT say):
- “Collision = bug in hashCode” — no, collisions are normal, bug = ALWAYS returning a constant
- “On collision HashMap loses data” — no, equals finds the element inside the bucket
- “hashCode must be unique” — mathematically impossible for an infinite set
Related topics:
- [[04. What is a Collision in HashMap]]
- [[05. How HashMap Handles Collisions]]
- [[07. What is the equals() and hashCode() Contract]]
- [[08. If Two Objects Are Equal by equals(), What Can You Say About Their hashCode()]]