How do you implement hashCode() using Objects.hash(...), and what are its caveats?
answer
- hash(Object...) == Arrays.hashCode == 31*result + element.hashCode()
- null contributes 0 (null-safe)
- Hash the SAME fields equals() compares
- Single field: use Objects.hashCode(x), not Objects.hash(x)
- Varargs allocates an array + autoboxes primitives
basics
~10 sObjects.hash(field1, field2, ...) takes the fields that define equality and combines them into one int hash code. You return it from hashCode(): return Objects.hash(name, email);. It handles nulls automatically.
solid answer
~40 sObjects.hash(Object...) computes a combined hash code from a sequence of values, internally using the same algorithm as Arrays.hashCode: start at 1, and for each element do result = 31 * result + (element == null ? 0 : element.hashCode()). You pass the exact fields used in equals(), in any consistent order, and return the result from hashCode(). It's null-safe (null contributes 0). Two caveats: (1) calling it with varargs autoboxes primitives and allocates an Object[] every call, so for very hot paths a hand-written hashCode avoids that overhead - though usually it's negligible. (2) The fields you hash must match the fields you compare in equals(), or you break the equals/hashCode contract (equal objects must share a hash code). For a single field prefer Objects.hashCode(x), since Objects.hash(x) wraps it in an array unnecessarily.
code
java · 27 linesimport java.util.Objects;
final class User {
private final String name; // nullable
private final String email;
private final int age;
User(String name, String email, int age) {
this.name = name; this.email = email; this.age = age;
}
@Override public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User other)) return false;
return age == other.age
&& Objects.equals(name, other.name)
&& Objects.equals(email, other.email);
}
@Override public int hashCode() {
// SAME fields as equals -> contract holds. null-safe; age is autoboxed.
return Objects.hash(name, email, age);
}
}
// Single field: prefer the singular helper (no array allocation):
// return Objects.hashCode(name); // NOT Objects.hash(name)go deeper
Can use Objects.hash(field1, field2) to implement hashCode and knows it must accompany equals.
Explains the 31*result+element algorithm, null-safety, and that hash fields must match equals fields.
Knows the varargs allocation/autoboxing cost, the single-field Objects.hashCode footgun, and when a hand-written hashCode is justified.
Reasons about hash distribution/collisions, contract enforcement across a codebase, IDE/record generation vs hand-rolling, and performance trade-offs in hot paths.
## Background: why hashCode exists Every Java object has a `hashCode()` method returning an `int`. Hash-based collections - `HashMap`, `HashSet`, `Hashtable` - use it to decide which 'bucket' an object goes into for fast lookup. The **contract** linking it to `equals()` is non-negotiable: 1. If `a.equals(b)` is true, then `a.hashCode() == b.hashCode()` **must** be true. 2. (The reverse need not hold - unequal objects may share a hash code, a 'collision', which is fine.) 3. `hashCode()` must be consistent (same value across calls while the object is unchanged). Break rule 1 and your objects vanish in a `HashMap`: you `put` then can't `get` them, because the map looks in the wrong bucket. ## What Objects.hash does `Objects.hash(Object... values)` is a static helper (Java 7+) that combines several values into a single, well-distributed `int`. It is literally implemented as: ```java public static int hash(Object... values) { return Arrays.hashCode(values); } ``` and `Arrays.hashCode` runs the classic polynomial accumulation: ```java int result = 1; for (Object element : values) result = 31 * result + (element == null ? 0 : element.hashCode()); return result; ``` Key points: - **31** is the multiplier (an odd prime; `31*x` compiles to `(x<<5)-x`). It mixes bits so different field orders/values give different results. - **null contributes 0** - so it's null-safe; you can pass nullable fields directly. - It returns the same `int` every time for the same inputs (deterministic). ## How you use it Implement `hashCode()` by passing exactly the fields your `equals()` uses: ```java @Override public int hashCode() { return Objects.hash(name, email, age); } ``` Pair it with an `equals()` built from `Objects.equals(...)` over the **same** fields. Same field set in both = contract satisfied. ## Caveats **1. Varargs allocation / autoboxing.** Because the parameter is `Object...`, every call: - allocates a new `Object[]` to hold the arguments, and - autoboxes any primitives (e.g. `int age` becomes an `Integer`). This is a small, fixed cost - irrelevant for most code, but in extremely hot loops (millions of calls) a hand-written `hashCode` (`int h = 17; h = 31*h + name.hashCode(); ...`) avoids the allocation. Don't prematurely optimize; measure first. **2. Single argument footgun.** `Objects.hash(x)` still builds a one-element array and runs the loop, giving `31 * 1 + x.hashCode()` - which is NOT the same number as `x.hashCode()`. For a single field call `Objects.hashCode(x)` (singular) instead, which is just `x == null ? 0 : x.hashCode()` - no array, and the 'natural' value. **3. Order matters.** `Objects.hash(a, b)` and `Objects.hash(b, a)` generally differ. That's fine as long as you're consistent across calls; just don't reorder between runs. **4. Must mirror equals.** The cardinal rule: the fields you hash must be a subset/match of the fields that make two objects equal. Hashing a field that equals ignores can still satisfy the contract only if equal objects always have that field equal too - simplest is to use the identical field set. ## Objects.hash vs Objects.hashCode - `Objects.hash(Object...)` - combine **many** values (varargs). - `Objects.hashCode(Object)` - null-safe hash of **one** value (returns 0 for null). Use this for a single field.
- Why is Objects.hash(x) for a single field considered wasteful or surprising?It wraps x in a new Object[] and returns 31*1 + x.hashCode(), allocating an array and giving a different value than x.hashCode(). For one field, Objects.hashCode(x) is cheaper and returns the natural hash.
- What breaks if hashCode() and equals() use different field sets?You can violate 'equal objects have equal hash codes'. Then two objects that are equal() may hash to different buckets in a HashMap/HashSet, so you can put an object and fail to get/find it later.
saying these in an interview costs you the question
- Objects.hash(x) equals x.hashCode() (false - it's 31 + x.hashCode())
- Hashing different fields than equals compares (breaks the contract)
- Thinking unequal objects must have different hash codes (collisions are legal)
- Claiming it throws on null fields (null becomes 0)