Java - Object Class Methods in Java
In Java, every class implicitly or explicitly inherits from the Object class, which is the root class of the Java class hierarchy. This means that methods defined in Object are available to almost every Java object.
The Object class belongs to the java.lang package, which is automatically imported into every Java program.
Understanding these methods is important because they are frequently used when comparing objects, displaying object information, checking object identity, and working with hash-based collections.
1. What is the Object Class?
The Object class is the superclass of all Java classes.
For example:
class Student {
String name;
int age;
}
Although Student does not explicitly extend another class, Java treats it approximately as:
class Student extends Object {
String name;
int age;
}
Therefore, a Student object can use methods inherited from Object.
Some of the commonly used methods are:
-
toString() -
equals() -
hashCode() -
getClass() -
clone() -
finalize()in older Java versions -
wait() -
notify() -
notifyAll()
Among these, toString(), equals(), hashCode(), and getClass() are especially important for general Java programming.
2. toString() Method
The toString() method returns a string representation of an object.
Its basic declaration in Object is:
public String toString()
When an object is printed using System.out.println(), Java automatically calls its toString() method.
Consider:
class Student {
String name;
int age;
Student(String name, int age) {
this.name = name;
this.age = age;
}
}
Now:
Student s = new Student("Rahul", 20);
System.out.println(s);
If toString() is not overridden, the output will generally look similar to:
Student@5acf9800
This output is not very useful because it represents the class name and an identity-based hexadecimal value.
We can override toString() to provide meaningful information:
class Student {
String name;
int age;
Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Name: " + name + ", Age: " + age;
}
}
Now:
Student s = new Student("Rahul", 20);
System.out.println(s);
Output:
Name: Rahul, Age: 20
Why is toString() useful?
It is useful when:
-
displaying object information
-
debugging programs
-
logging objects
-
understanding the contents of an object
-
producing readable output
3. equals() Method
The equals() method is used to compare objects.
Its declaration is:
public boolean equals(Object obj)
It returns either true or false.
A common misunderstanding is that equals() always compares the contents of two objects. That is not automatically true.
The default implementation inherited from Object essentially checks whether two references represent the same object.
For example:
Student s1 = new Student("Rahul", 20);
Student s2 = new Student("Rahul", 20);
System.out.println(s1.equals(s2));
Without overriding equals(), the result will generally be:
false
Even though both students have the same name and age, s1 and s2 are two different objects.
Overriding equals()
If we want two Student objects to be considered equal when their data is the same, we can override equals().
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
Student student = (Student) obj;
return age == student.age && name.equals(student.name);
}
Now:
Student s1 = new Student("Rahul", 20);
Student s2 = new Student("Rahul", 20);
System.out.println(s1.equals(s2));
Output:
true
This is called logical equality, where objects are considered equal based on their data rather than their memory identity.
4. hashCode() Method
The hashCode() method returns an integer hash value associated with an object.
Its declaration is:
public int hashCode()
For example:
Student s = new Student("Rahul", 20);
System.out.println(s.hashCode());
The exact number can vary.
The method becomes particularly important when objects are used in hash-based collections such as HashMap and HashSet.
Relationship between equals() and hashCode()
There is an important rule:
If two objects are equal according to equals(), they must return the same hashCode() value.
For example, if:
s1.equals(s2)
returns:
true
then:
s1.hashCode() == s2.hashCode()
must also be true.
However, the reverse is not necessarily true. Two objects can have the same hash code while still not being equal.
Example
When overriding equals(), it is generally necessary to override hashCode() as well.
@Override
public int hashCode() {
return java.util.Objects.hash(name, age);
}
A complete example would therefore contain both methods:
class Student {
String name;
int age;
Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
Student student = (Student) obj;
return age == student.age && name.equals(student.name);
}
@Override
public int hashCode() {
return java.util.Objects.hash(name, age);
}
}
This allows the class to behave correctly when used with hash-based collections.
5. getClass() Method
The getClass() method returns information about the runtime class of an object.
Its declaration is:
public final Class<?> getClass()
Example:
Student s = new Student("Rahul", 20);
System.out.println(s.getClass());
Output will be similar to:
class Student
You can also obtain the class name:
System.out.println(s.getClass().getName());
Output:
Student
Depending on the package, the fully qualified class name may be displayed.
Why is getClass() useful?
It can be used for:
-
identifying an object's runtime type
-
runtime type checking
-
reflection-related operations
-
comparing the exact classes of objects
-
debugging
For example:
if (s1.getClass() == s2.getClass()) {
System.out.println("Both objects belong to the same class.");
}
6. wait() Method
The wait() method is associated with Java's object-monitor mechanism and thread synchronization.
Its commonly used form is:
public final void wait() throws InterruptedException
When a thread calls wait() on an object while owning that object's monitor, the thread waits until another thread notifies it.
Example conceptually:
synchronized (obj) {
obj.wait();
}
Another thread can notify the waiting thread:
synchronized (obj) {
obj.notify();
}
wait() should therefore be understood together with notify() and notifyAll().
These methods are primarily relevant when learning Java concurrency and synchronization.
7. notify() Method
The notify() method wakes up one thread that is waiting on the object's monitor.
Example:
synchronized (obj) {
obj.notify();
}
The thread that receives the notification does not immediately continue execution merely because it was notified. It must first reacquire the object's monitor.
8. notifyAll() Method
The notifyAll() method wakes all threads waiting on the object's monitor.
Example:
synchronized (obj) {
obj.notifyAll();
}
The waiting threads then compete to acquire the monitor.
The difference is:
notify() → wakes one waiting thread
notifyAll() → wakes all waiting threads
9. clone() Method
The clone() method can be used to create a copy of an object when the class supports Java's cloning mechanism.
Its declaration in Object is:
protected native Object clone() throws CloneNotSupportedException
A class generally needs to implement Cloneable to use the conventional clone() mechanism successfully.
Example:
class Student implements Cloneable {
String name;
Student(String name) {
this.name = name;
}
@Override
public Student clone() throws CloneNotSupportedException {
return (Student) super.clone();
}
}
Then:
Student s1 = new Student("Rahul");
Student s2 = s1.clone();
Here, s2 is a separate object created as a copy of s1.
However, cloning has several subtleties, particularly concerning shallow versus deep copying, so modern Java code often uses constructors, factory methods, or other explicit copying approaches instead of relying heavily on clone().
10. finalize() Method
Historically, Object included:
protected void finalize()
It was associated with cleanup before an object was reclaimed by the garbage collector.
However, finalization is deprecated and should not be used in modern Java programs. It is not a reliable mechanism for resource management.
Resources such as files, database connections, and network connections should instead be managed using appropriate APIs, particularly try-with-resources for AutoCloseable resources.
Therefore, finalize() is mainly important from a historical and examination perspective rather than as a recommended programming technique.
11. Difference Between == and equals()
This is one of the most important concepts related to the Object class.
The == operator and equals() method are not the same.
Using ==
For objects, == checks whether two references point to the same object.
Student s1 = new Student("Rahul", 20);
Student s2 = new Student("Rahul", 20);
System.out.println(s1 == s2);
Output:
false
They are separate objects.
Using equals()
If equals() has been properly overridden to compare student data:
System.out.println(s1.equals(s2));
Output:
true
Therefore:
== → reference identity
equals() → logical equality, when properly overridden
12. Important Relationship Between equals() and hashCode()
Suppose:
Student s1 = new Student("Rahul", 20);
Student s2 = new Student("Rahul", 20);
If:
s1.equals(s2)
is true, then:
s1.hashCode() == s2.hashCode()
must also be true.
This rule is particularly important when using:
HashSet
HashMap
For example, if two logically equal objects have different hash codes, hash-based collections may not behave as expected.
Therefore, whenever you override equals(), you should normally override hashCode() consistently.
13. Why Object Class Methods Are Important
The methods of Object form the foundation for many Java programming concepts.
They help programmers:
-
represent objects as readable text
-
compare objects
-
determine object identity
-
generate hash values
-
identify runtime classes
-
copy objects when appropriate
-
coordinate threads
-
work correctly with hash-based collections
Because every ordinary Java class ultimately inherits from Object, these methods are available throughout Java's object-oriented programming model.
Summary
| Method | Main Purpose |
|---|---|
toString() |
Provides a string representation of an object |
equals() |
Compares objects for logical equality when overridden appropriately |
hashCode() |
Produces a hash value used heavily by hash-based collections |
getClass() |
Identifies the object's runtime class |
clone() |
Supports object copying through Java's cloning mechanism |
wait() |
Makes a thread wait on an object's monitor |
notify() |
Wakes one waiting thread |
notifyAll() |
Wakes all waiting threads |
finalize() |
Historical cleanup mechanism; deprecated and not recommended |
The most important methods for everyday Java programming are toString(), equals(), hashCode(), and getClass(). Understanding how these methods work is essential for writing well-behaved Java classes, especially when objects are compared, displayed, or stored in collections.