What does the default Object.hashCode() return, and what does 'not stable across JVM runs' mean for it?
answer
- Default = per-instance identity hash, not address
- GC moves objects -> address can't be the hash
- Stable within a run, NOT across runs
- Distinct objects -> different codes (matches == equals)
- System.identityHashCode bypasses overrides
basics
~20 sIf a class doesn't override hashCode(), it gets an identity hash: a number tied to that specific object instance, the same every time you ask during one run. It is not the memory address, and a fresh run of the program can produce different numbers.
solid answer
~50 sWithout an override, an object inherits `Object.hashCode()`, which returns an **identity hash code** — a per-instance integer the JVM computes (often lazily) and then keeps stable for that object's lifetime within the run. It is *not* the memory address (the garbage collector relocates objects, so the address can't be the identity), and it is *not* derived from the object's fields, so two field-identical-but-distinct objects get different codes — matching the default `equals`, which is reference identity. 'Not stable across JVM runs' means there is no guarantee the same logical object yields the same int when you restart the program; the identity hash is generated per run (and some JVM modes randomize the seed). You can still obtain this value for any object, even one that overrides hashCode, via `System.identityHashCode(obj)`. Practical consequence: never persist or transmit a hashCode expecting it to be reproducible later.
code
java · 9 linesclass Box { int v; Box(int v){ this.v = v; } } // no hashCode override
Box a = new Box(5);
Box b = new Box(5); // same field value, different instance
a.hashCode() == a.hashCode(); // true: stable within the run
a.hashCode() == b.hashCode(); // almost always FALSE: identity, not value
System.identityHashCode(a); // the identity hash, bypassing any override
// On a fresh JVM run, a.hashCode() may print a different number than last time.go deeper
Knows that without an override hashCode is tied to the specific object, stable during the run, and that equal-content objects don't automatically share it.
Explains it's an identity hash (not the address, because GC moves objects), consistent within a run but not across runs, and matches the identity-based default equals.
Discusses where the identity hash is stored (object header), JVM hashCode strategies / randomization, System.identityHashCode and IdentityHashMap, and why persisting hashCodes is unsafe.
Reasons about header-word pressure from stored identity hashes, biased-locking/header interactions historically, and sets guidance that any cross-process identifier must be an explicit field, never a hashCode.
## The default behavior Every class that does **not** override `hashCode()` uses `java.lang.Object`'s implementation. This returns an **identity hash code**: an `int` associated with the *identity* of that specific object instance. Key properties: - **Per-instance, not per-value.** Two *distinct* objects — even with identical field contents — get (almost always) *different* identity hashes. This is deliberately consistent with `Object.equals`, whose default is reference identity (`a == b`): only the very same object is equal to itself, and only it shares its identity hash. - **Stable within a run.** Once computed for an object, the value is cached (commonly in the object's header word) and returned unchanged for the rest of that object's life, satisfying the contract's consistency clause. - **Not the memory address.** A common misconception is that it's the pointer. It cannot be, because the JVM's garbage collector **moves** objects in memory during compaction; if the hash were the address, it would change when the object moved, breaking consistency. So the JVM computes a separate identity value (e.g. from a thread-local PRNG, or a global counter, depending on the `-XX:hashCode` strategy) and stores it. ## 'Not stable across JVM runs' The contract only promises consistency *within a single execution*. The identity hash is generated **fresh each run** — and several JVM configurations seed it from a randomized source, so the same logical object created in two different program executions will typically receive **different** identity hashes. Therefore: - You must **never persist** a hashCode (to a file, database, or cache key on disk) and rely on it matching after a restart. - You must **never send** a hashCode over the network as a stable identifier between processes. - Reproducible test assertions must not hard-code expected hashCode values for default-hash objects. The same caveat technically applies even to *overridden* hashCodes if they depend on per-run data, but a well-written value-based hashCode (derived purely from stable field values) **will** reproduce across runs — it's the *identity* default specifically that won't. ## Accessing it explicitly `System.identityHashCode(obj)` returns the identity hash for *any* object, **bypassing** any overridden `hashCode()`. This is occasionally useful for identity-based diagnostics or `IdentityHashMap`, which keys by `==` and identity hash rather than `equals`/`hashCode`. ## Why this matters Understanding the default explains two everyday facts: (1) why putting an *un-overridden* value object into a `HashSet` and then looking it up with a freshly constructed equal object **fails** (different identity hashes), and (2) why you should override *both* `equals` and `hashCode` together when you want value semantics. The default is correct and self-consistent; it simply implements *identity*, not *equality of content*.
- Is the default hashCode the object's memory address?No. The GC can relocate objects during compaction, so the address isn't stable. The JVM instead computes a separate identity value (per its hashCode strategy) and caches it in the object header, keeping it stable for the object's lifetime in that run.
- If I override hashCode from immutable fields, will it reproduce across runs?Yes, generally. A value-based hashCode computed purely from stable field values produces the same int wherever those values are the same, across runs and JVMs. The cross-run instability is specific to the identity default (and any hash depending on per-run state).
The identity hash is like a coat-check ticket number handed out when you arrive: unique to you for today's visit and the same all evening, but the numbering restarts (and may be shuffled) tomorrow. It says nothing about what your coat looks like — only that this ticket is yours, this visit.
saying these in an interview costs you the question
- Saying the default hashCode is the memory address
- Assuming two field-equal objects share the default hashCode
- Expecting default hashCodes to be reproducible after restart
- Confusing System.identityHashCode with the overridden hashCode