skip to content

How do you implement hashCode() using Objects.hash(...), and what are its caveats?

level: middleimportance: must knowfreq 68%

answer

  1. hash(Object...) == Arrays.hashCode == 31*result + element.hashCode()
  2. null contributes 0 (null-safe)
  3. Hash the SAME fields equals() compares
  4. Single field: use Objects.hashCode(x), not Objects.hash(x)
  5. Varargs allocates an array + autoboxes primitives

basics

~10 s

Objects.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 s

Objects.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 lines
java
import 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

for a junior

Can use Objects.hash(field1, field2) to implement hashCode and knows it must accompany equals.

for a middle

Explains the 31*result+element algorithm, null-safety, and that hash fields must match equals fields.

for a senior

Knows the varargs allocation/autoboxing cost, the single-field Objects.hashCode footgun, and when a hand-written hashCode is justified.

for a principal

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)

context