skip to content

What is the hashCode() contract in Java? State its rules.

level: juniorimportance: must knowfreq 82%

answer

  1. Equal objects -> equal hashCodes (the load-bearing rule)
  2. Consistent within ONE run only
  3. Unequal MAY collide (allowed, just slower)
  4. Same fields as equals, no more no less
  5. Default = per-run identity hash, not address

basics

~20 s

hashCode() returns an int for an object. Two rules matter: if two objects are equal (equals() is true), they must return the same hashCode; and a hashCode must stay the same across repeated calls during one run. Unequal objects may share a code.

solid answer

~40 s

The hashCode() contract has three parts. First, consistency: as long as the object's equals-relevant state is unchanged, repeated hashCode() calls in the same JVM run must return the same int. Second, the equals link: if a.equals(b) is true, then a.hashCode() == b.hashCode() must hold. Third, the collision allowance: if two objects are unequal, their hashCodes are not required to differ — they may collide; producing distinct codes for unequal objects merely improves hash-table performance. Note what the contract does NOT promise: hashCode values are not stable across different JVM runs (the default identity hash is derived per-run), and unequal objects with equal codes are perfectly legal. Hash-based collections (HashMap, HashSet) rely on the equals link being honored, which is why overriding equals without overriding hashCode breaks them.

code

java · 18 lines
java
final class Point {
    private final int x, y;
    Point(int x, int y) { this.x = x; this.y = y; }

    @Override public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Point p)) return false;
        return x == p.x && y == p.y;
    }

    // Derived from the SAME fields equals uses -> equal objects get equal codes.
    @Override public int hashCode() {
        return java.util.Objects.hash(x, y);
    }
}

// new Point(1,2).hashCode() == new Point(1,2).hashCode()  // true: required by rule 2
// new Point(1,2).equals(new Point(1,2))                   // true

go deeper

for a junior

Can state the headline rule: equal objects must have equal hashCodes, and a code is stable while the object doesn't change. Knows hashCode returns an int used by HashMap/HashSet.

for a middle

States all three clauses (consistency, equals-link, collisions allowed) and explains why violating the equals-link loses entries in a HashMap. Knows to derive hashCode from the same fields as equals.

for a senior

Articulates the negative space too — no cross-run stability, equal codes don't imply equality, default is a per-run identity hash (not the address). Can reason about distribution quality vs. mere correctness.

for a principal

Frames it as an API invariant other code depends on; discusses caching hashCode for immutable types, collision-resistance vs. performance, and the security angle (predictable hashes enabling hash-flooding DoS).

## What hashCode() is Every Java object inherits a method `int hashCode()` from `java.lang.Object`. It returns a 32-bit integer (`int`) meant to be a *condensed numeric fingerprint* of the object. Its primary consumer is the family of **hash-based collections** — `HashMap`, `HashSet`, `Hashtable`, `ConcurrentHashMap` — which store entries in an array of "buckets." To decide which bucket an object goes in, the collection takes the object's hashCode and maps it (via further mixing and a modulo by the array length) to a bucket index. A good hashCode spreads objects evenly across buckets so each bucket holds few items and lookups stay close to O(1). ## The contract, rule by rule The Javadoc of `Object.hashCode()` states a **contract** every override must obey: 1. **Self-consistency (within one run).** Whenever `hashCode()` is invoked more than once on the *same* object during a single execution of an application, it must consistently return the same integer — **provided no information used in `equals` comparisons is modified**. The qualifier matters: if you mutate a field that participates in equals/hashCode, the code may (and usually will) change. 2. **The equals link (the load-bearing rule).** If two objects are equal according to `equals(Object)`, then calling `hashCode()` on each **must** produce the same integer result. Formally: `a.equals(b) == true` ⟹ `a.hashCode() == b.hashCode()`. 3. **The collision allowance.** It is **not** required that unequal objects produce distinct hashCodes. Two objects that are *not* equal may legally return the same int — this is a **collision**. The Javadoc only *encourages* distinct results for unequal objects because doing so improves the performance of hash tables; it is not a correctness requirement. ## What the contract deliberately does NOT promise - **No cross-run stability.** A hashCode is only required to be consistent *within a single JVM execution*. The same object (same logical value) may return a different int the next time you start the program. This is most visible with the **default identity hash** (see below), which `Object` derives per-run and is *not* the memory address. Therefore you must never persist a hashCode to disk or send it across the network expecting it to match later. - **No reverse implication.** Equal hashCodes do **not** imply equal objects. `a.hashCode() == b.hashCode()` tells you nothing about `a.equals(b)`; it just means they may land in the same bucket, where `equals` is then used to tell them apart. ## The default identity hash If a class does **not** override `hashCode()`, it inherits `Object.hashCode()`, which returns an **identity hash code**: a value associated with the object's identity (each distinct object instance), computed and cached by the JVM. It is *not* the memory address (the GC can move objects), but a per-object, per-run number. Consequently the default `hashCode` is consistent with the default `equals` (which is reference identity `==`): two references to the *same* object give the same code; two *distinct* objects give (almost always) different codes, even if their fields are identical. ## Why the equals link matters in practice When you `put` a key into a `HashMap`, it computes the key's hashCode to choose a bucket. When you later `get` with an *equal* key, it recomputes the hashCode to find the bucket, then walks that bucket comparing with `equals`. If two equal objects produced *different* hashCodes, the lookup would probe the wrong bucket and the entry would appear missing — the object becomes "lost" in the collection. That is the concrete failure mode of violating rule 2, and it is why overriding `equals` *obligates* you to override `hashCode` consistently. ## How to satisfy it Derive the hashCode from **exactly the same fields** that `equals` uses, and from no others. The simplest correct implementation in modern Java is `java.util.Objects.hash(field1, field2, ...)`. Records generate a compliant `hashCode` automatically from their components.

  • If two objects have the same hashCode, must they be equal?
    No. Equal hashCodes do not imply equality — that is a collision, which the contract explicitly permits. The collection still calls equals() to distinguish them. Only the reverse holds: equal objects must have equal hashCodes.
  • Can you cache a hashCode value to disk and rely on it next run?
    No. The contract only guarantees consistency within a single JVM run. Across runs the value may differ (especially the default identity hash), so persisting it is unsafe. Recompute it from the object's state each run instead.

A hashCode is like the first letter of a surname used to file documents in labeled drawers. Two identical documents must file under the same letter (equal -> equal code). Different surnames can share a letter (collisions allowed). And the filing scheme is only valid for this office's setup today — another office may letter things differently (no cross-run stability).

saying these in an interview costs you the question

  • Claiming hashCode must be unique for unequal objects (collisions are allowed)
  • Claiming equal hashCodes mean the objects are equal
  • Believing hashCode is the object's memory address
  • Assuming hashCode is stable across JVM restarts
  • Saying you can override equals without touching hashCode

context