All 15 equals(), hashCode() & toString() Contracts questions
More in equals(), hashCode() & toString() Contracts
Advertisement
Java › equals(), hashCode() & toString() Contracts

How does Java Record's automatically-generated equals(), hashCode(), and toString() implementations work, and in what specific ways do they differ from a manually-written, field-by-field implementation?

Advanced

Answer

A record automatically generates equals() (comparing all component fields via their own equals(), using Arrays.equals() semantics for array-typed components specifically, meaning two records with array components are compared element-wise rather than by array reference), hashCode() (combining all component fields' hash codes), and toString() (a consistent format like RecordName[field1=value1, field2=value2]) entirely without any code, tied directly to the record's declared components -- this is functionally very close to a well-written manual implementation using Objects.equals()/Objects.hash(), with the specific exception that array-typed components in the generated equals()/hashCode() use a shallow, IDENTITY-based comparison for the array reference itself (NOT Arrays.equals() semantics) unless you explicitly override equals()/hashCode() yourself, a common surprise for records containing array fields.
public record Point(int x, int y) {}
// Automatically gets: equals() comparing x and y, hashCode() combining them, and
// toString() producing "Point[x=3, y=4]" -- all without writing a single line of boilerplate

public record Data(int[] values) {}
Data d1 = new Data(new int[]{1,2,3});
Data d2 = new Data(new int[]{1,2,3});
System.out.println(d1.equals(d2));  // FALSE! Array components compare by reference, not content, by default
Real-world example A team migrating a manually-written value class to a record saves dozens of lines of equals()/hashCode()/toString() boilerplate, but is later surprised when a record containing an int[] field doesn't behave as expected in a Set, tracing the issue to the record's auto-generated equals() using array reference comparison rather than Arrays.equals() content comparison, requiring an explicit manual equals() override for that specific record.

Common follow-ups: Why did the record specification choose reference-based comparison for array components rather than automatically using Arrays.equals()?;How would you override just equals()/hashCode() for a record while keeping the other auto-generated members?