Introduction
Everything in Java extends from a single class: java.lang.Object
. Whether you're writing a basic class or using advanced frameworks like Spring or Hibernate, you're always dealing with the Object class behind the scenes.
Three of its most commonly used methods are:
equals()
– used for comparing objectshashCode()
– used in hashing collections likeHashMap
toString()
– used for printing/debugging
Overriding these methods properly is essential for writing clean, correct, and scalable code. In this guide, we’ll dive deep into how they work, when to override them, and how they impact your Java applications.
What is the Object Class?
The Object
class is the root of the Java class hierarchy. All classes—built-in or user-defined—implicitly extend it.
class MyClass {
// implicitly extends Object
}
Methods in the Object Class
Key methods include:
equals(Object obj)
hashCode()
toString()
clone()
getClass()
notify()
,notifyAll()
,wait()
This article focuses on the three most used and most frequently overridden: equals()
, hashCode()
, and toString()
.
equals() Method
Purpose
Checks whether two objects are logically equal (not just reference equal).
Default Behavior
public boolean equals(Object obj) {
return (this == obj);
}
When to Override
When comparing object content instead of reference.
Custom equals() Example
class User {
String name;
User(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
User user = (User) obj;
return name.equals(user.name);
}
}
hashCode() Method
Purpose
Returns an integer hash code used in hash-based collections like HashMap
, HashSet
.
Default Behavior
Generates unique hash per object (usually based on memory address).
Contract with equals()
- If
a.equals(b)
, thena.hashCode() == b.hashCode()
must be true - If
a.hashCode() != b.hashCode()
, thena.equals(b)
can be false
Custom hashCode() Example
@Override
public int hashCode() {
return name.hashCode();
}
Use Objects.hash(...)
for multiple fields:
@Override
public int hashCode() {
return Objects.hash(name, age);
}
toString() Method
Purpose
Returns a string representation of the object (used in logging, debugging, printing).
Default Behavior
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
Overriding Example
@Override
public String toString() {
return "User{name='" + name + "'}";
}
UML Representation
<<class>> Object
+ equals(Object): boolean
+ hashCode(): int
+ toString(): String
<<class>> User extends Object
+ equals(Object): boolean
+ hashCode(): int
+ toString(): String
Real-World Example: HashMap with Custom Keys
Map<User, String> map = new HashMap<>();
User u1 = new User("Alice");
User u2 = new User("Alice");
map.put(u1, "Engineer");
// Without equals() and hashCode(), u2 will not be found
System.out.println(map.get(u2)); // null
✅ Fix: Override equals()
and hashCode()
properly.
Java 16+ Records and Object Methods
Java records auto-generate:
equals()
hashCode()
toString()
record User(String name, int age) {}
Prints:
User[name=Alice, age=30]
Common Pitfalls
❌ Inconsistent equals() and hashCode()
Overriding equals()
without hashCode()
breaks collections.
❌ Reference Comparison in equals()
Use .equals()
for object fields, not ==
.
Best Practices
- Always override
hashCode()
if you overrideequals()
- Use
Objects.equals()
andObjects.hash()
for null-safety - Use IDEs to generate boilerplate safely
- Prefer records if you need value classes with equals/hashCode
Real-World Analogy
equals()
is like comparing the contents of two books.hashCode()
is like the library catalog number—helps you find the book faster.toString()
is like the book summary on the back cover.
Conclusion
The Object
class forms the core of Java's object model. Overriding equals()
, hashCode()
, and toString()
gives your objects identity, predictability, and readability.
Whether you're using collections, debugging, or modeling business entities, these methods help build robust and maintainable software.
Key Takeaways
- All Java classes inherit from
Object
equals()
compares content;==
compares referenceshashCode()
must align withequals()
to work with collectionstoString()
improves debugging and logging- Java records provide default implementations of all three
FAQs
1. Is equals()
the same as ==
?
No. equals()
checks content; ==
checks references.
2. What happens if I override equals()
but not hashCode()
?
You break the contract—collections like HashSet
may not work correctly.
3. Can I override equals()
using instanceof
?
Yes, but prefer getClass()
if you need strict type checks.
4. Are hashCode()
values unique?
Not necessarily—collisions are allowed but should be minimized.
5. Why should I override toString()
?
To get human-readable output for logging and debugging.
6. Can I use ==
for string comparison?
No. Use .equals()
for value comparison.
7. Does record
override equals()
and hashCode()
?
Yes. Records auto-generate value-based equality methods.
8. What is the default toString()
output?
It returns something like User@7ad041f3
.
9. Is Objects.hash()
efficient?
Yes, and it simplifies multi-field hash generation.
10. Do I need to override equals()
in every class?
No. Only override it if you plan to compare object content or use the class in collections.