Beginner · Classes and objects · topic 20 of 60 · 30 min
toString, equals, hashCode and records
Explanation
What every object inherits
Every Java class extends java.lang.Object, directly or indirectly, and inherits methods including toString(), equals(Object) and hashCode(). The default versions are rarely what you want: toString prints something like Product@1b6d3586, and equals behaves like == (same object only).
toString
public class Product {
private final String sku;
private final double price;
public Product(String sku, double price) { this.sku = sku; this.price = price; }
@Override
public String toString() {
return "Product[sku=" + sku + ", price=" + price + "]";
}
}
System.out.println(new Product("PEN-01", 20)); // Product[sku=PEN-01, price=20.0]equals and hashCode: a contract
equals decides whether two objects are "the same value" (two Product objects with the same SKU, for example). hashCode returns an int used by hash-based collections (HashMap, HashSet) to decide which bucket an object goes into. The contract: if a.equals(b) is true, then a.hashCode() must equal b.hashCode(). If you override equals but not hashCode, two equal objects land in different buckets and a HashSet will happily store both "duplicates".
import java.util.Objects;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Product other)) return false; // pattern matching (Java 16+)
return sku.equals(other.sku);
}
@Override
public int hashCode() {
return Objects.hash(sku); // same fields as equals
}Records: data classes in one line
Many classes just carry data: a DTO from an API, a point, a money amount. Writing fields, a constructor, getters, equals, hashCode and toString by hand is long and error-prone. A record (Java 16+) declares the components once, and the compiler generates the rest. Records are immutable: their fields are private and final, and there are no setters.
public record Product(String sku, double price) { }
Product p = new Product("PEN-01", 20);
System.out.println(p.sku()); // accessor is sku(), not getSku()
System.out.println(p); // Product[sku=PEN-01, price=20.0]
System.out.println(p.equals(new Product("PEN-01", 20))); // true (all components compared)Compact constructors for validation
public record Money(long paise, String currency) {
public Money { // compact constructor: no parameter list
if (paise < 0) throw new IllegalArgumentException("Negative amount");
currency = currency.toUpperCase(); // you may normalise parameters before they are stored
}
public Money plus(Money other) { return new Money(paise + other.paise, currency); }
}Records can have methods and static members, and can implement interfaces, but cannot extend another class and cannot declare extra instance fields. Use a normal class when the object needs mutable state or inheritance.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
toString, equals, hashCode and records · 1/6
In this lesson you will give classes proper toString, equals and hashCode, and meet records.
Prefer a video by a teacher? Find free videos on “java equals hashcode contract records tutorial” on YouTube ↗
In real life: De-duplicating customers from two systems
After a bank merger, customer lists from two systems were combined into a HashSet to remove duplicates, keyed by PAN. Because the Customer class overrode equals but forgot hashCode, duplicates survived and some customers received two welcome letters. Turning Customer into a record keyed on PAN fixed it.
// A record compares ALL its components, so the de-duplication key holds only the PAN.
record CustomerKey(String pan) { }
var seen = new java.util.HashSet<CustomerKey>();
System.out.println(seen.add(new CustomerKey("ABCDE1234F"))); // true
System.out.println(seen.add(new CustomerKey("ABCDE1234F"))); // false: duplicatePractice (0/3 done)
class P { String id; P(String id) { this.id = id; } public boolean equals(Object o) { return o instanceof P p && p.id.equals(id); } } — no hashCode. What does this probably print? var set = new HashSet<P>(); set.add(new P("A")); System.out.println(set.contains(new P("A")));
record Point(int x, int y) {} Which line does NOT compile?
Write a class Book with isbn, title and price. Override toString, equals and hashCode so that two books are equal when their ISBN is equal. Prove it by adding two Book objects with the same ISBN to a HashSet and printing its size (it must be 1). Then rewrite Book as a record and explain in a comment why the record version compares all three fields.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Encapsulation: private fields, getters and settersClasses and objects · same module
- Classes, objects and constructorsC# and .NET · Classes and objects
- Data, enum and sealed classes, and objectsKotlin and Android App Development · Classes, objects and collections
- Records and pattern matchingC# and .NET · Inheritance, interfaces and records
- Inheritance with extendsInheritance, polymorphism and interfaces
- Inheritance: base and derived classesC# and .NET · Inheritance, interfaces and records
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
If a.equals(b) is true, what must be true?
Answer: a.hashCode() == b.hashCode()
That is the equals/hashCode contract.
What does @Override do?
Answer: Asks the compiler to check that the method really overrides a parent method
A typo in the signature becomes a compile error.
Which is TRUE about records?
Answer: They generate equals, hashCode and toString
Records are immutable data carriers with generated methods.
Default Object.equals behaves like…
Answer: ==, same object only
Without overriding, equals checks identity.
Without overriding ToString, what does printing an object of class City show?Related
Answer: Its class name (like City)
The default ToString returns the type's full name.
What does == compare for two data class objects?Related
Answer: Their property values
Data classes generate equals based on properties.
What does new Product("Pen", 10m).ToString() give for record Product(string Name, decimal Price)?Related
Answer: Product { Name = Pen, Price = 10 }
Records print their type name and properties.
How many classes can a Java class directly extend?Related
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- This is the last topic of “Classes and objects”. The module exam comes next.
- Module 4 exam: Classes and objects · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Inheritance, polymorphism and interfaces. 60 topics left in the course before the final exam.