liveBook · Manning

hashCode method

As explained in 100 Java Mistakes and How to Avoid Them

The hashCode method is a Java object method that returns an integer hash value consistent with the object's equality contract.

`hashCode()` returns an integer used alongside `equals()` in Java object comparison. The essential rule is simple: objects considered equal must produce the same hash value. Breaking that relationship can make equality-based data structures behave unpredictably and create difficult debugging problems. section 7.0 section 7.8

The risk rises when `equals()` has nonstandard logic. If a two-field object treats `(f1, f2)` and `(f2, f1)` as equal, `Objects.hash(f1, f2)` is wrong because its result depends on argument order. A symmetric calculation such as `f1 + f2` matches that equality rule. Alternatively, normalize field order when constructing or modifying an immutable object; ordinary generated `equals()` and `hashCode()` then work. section 7.8

class TwoFields {
  int f1, f2;

  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    TwoFields twoFields = (TwoFields) o;
    return f1 == twoFields.f1 && f2 == twoFields.f2 ||
           f1 == twoFields.f2 && f2 == twoFields.f1;
  }
}

This equality relation ignores field order, so its matching hash calculation must also ignore field order. The associated `f1 + f2` implementation supplies a symmetric hash. section 7.8

Case-insensitive equality can defeat case normalization

Using `equalsIgnoreCase()` for equality does not make `toLowerCase(Locale.ROOT).hashCode()` automatically safe. Some strings compare equal ignoring case while lowercasing produces different results, violating the contract. The illustrated Greek sigma values can compare equal yet cause a `Set` lookup to vary with the set’s contents. If preserving original case prevents construction-time normalization, make the equality and hashing transformations agree exactly. section 7.8

Avoid hand-written mismatch errors with practical safeguards:

  • Generate `equals()` and `hashCode()` together in an IDE, especially after adding fields. section 7.15 section 7.6
  • Use records for data holders when possible; Java 16 records receive compiler-generated `equals()` and `hashCode()` implementations. section 7.6
  • Test custom equality with EqualsVerifier rather than relying only on manual cases. section 7.6
  • Treat static-analysis warnings about comparison code as prompts for close inspection, not as warnings to suppress automatically. section 7.6

`hashCode()` is only one part of a broader comparison contract that includes `equals()`, `Comparable.compareTo()`, and `Comparator.compare()`. These methods are used implicitly by algorithms such as sorting and by structures such as `HashMap`, so comparison code should follow its documented contract rather than depend on accidental behavior. section 7.0 section 7.15

How 100 Java Mistakes and How to Avoid Them covers it

How deep it goes
Works through order-independent and case-insensitive equality cases, then gives generation, normalization, and verification safeguards.
Examples
Uses swapped integer fields and case-insensitive Greek sigma strings whose `Set` lookup exposes a broken hash contract.
What it assumes
Builds on familiarity with Java objects, fields, `equals()`, and equality-based collections rather than teaching them from zero.
What you can do after
Diagnose/debug with it by recognizing equality rules that require a corresponding symmetric or otherwise matching hash calculation.
How it connects
Connects `hashCode()` with `equals()`, `HashMap`, `Set`, Java records, `Objects.hash()`, and `EqualsVerifier`.

Also explained in

Compare how 2 books explain hashCode method →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of 100 Java Mistakes and How to Avoid Them. The section links point to the parts of the book it draws on.