The Object class is a fundamental class in Java that serves as the root of the class hierarchy. Inheriting from the Object class provides all classes in Java with several important methods that can be used to manipulate objects. In this tutorial, we’ll explore some of the most commonly used methods that are inherited from the Object class, including toString()
, equals()
, getClass()
, and clone()
. By the end of this tutorial, you’ll have a solid understanding of how to use these methods to work with objects in Java.
All Classes are Instances of Object Class
The Object class is the ultimate parent class in Java. All classes in Java directly or indirectly inherit the Object class. Therefore, all Java classes are considered to be instances of the Object class. Consider the following example:
class Vehicle { // ... } class Car extends Vehicle { // ... } class Test { public static void main(String[] args) { Vehicle vehicle = new Vehicle(); Car car = new Car(); System.out.println(vehicle instanceof Object); System.out.println(car instanceof Vehicle); System.out.println(car instanceof Car); } }
true true true
As you can see, the Car class inherits the Vehicle class, which is itself an instance of the Object class. Similarly, the Car class is an instance of both the Vehicle and the Object class.
In Java, all classes inherit some useful methods from the Object class, which we will discuss in the next section.
Inheriting Methods from the Object Class
Method | Description |
---|---|
public final Class getClass() | Returns the class object of the object it is called on, it is used to obtain information about the class of an object at runtime. |
public int hashCode() | Returns a unique integer value (called hash code) that represents the object. |
public boolean equals(Object obj) | Used to compare whether two objects are equal or not. It returns true if the two objects are equal, and false otherwise. |
protected Object clone() throws CloneNotSupportedException | Creates and returns a copy of the current object. It throws a CloneNotSupportedException if the object being cloned does not implement the Cloneable interface. |
public String toString() | Convert an object into a human-readable string representation, this method can be overridden by a subclass to provide a more appropriate string representation of the object. |
public final void notify() | Used in Java to wake up a single thread that is waiting on the object’s monitor. |
public final void notifyAll() | Used to wake up all threads that are waiting on a particular object. |
public final void wait() throws InterruptedException | Causes the current thread to pause execution and enter a waiting state until another thread notifies it to continue. If the thread is interrupted while waiting, it throws an InterruptedException. |
public final void wait(long timeout) throws InterruptedException | Causes the current thread to pause its execution and wait for a certain amount of time, specified by the timeout parameter. If the specified timeout elapses or the thread is interrupted, the method throws an InterruptedException. |
public final void wait(long timeout, int nanos) throws InterruptedException | Causes the current thread to wait for a specified amount of time (given in milliseconds and nanoseconds) until it is awakened by another thread or until the specified time has elapsed. |
protected void finalize() throws Throwable | Called by the garbage collector before an object is removed from memory. It can be overridden in a subclass to perform cleanup operations such as releasing system resources or closing files. |
We will take a closer look at some of the most interesting and useful methods inherited from the Object class in Java. We will explore their functionality and usage, and provide examples of how to implement them in our own Java programs:
The toString()
Method
The toString()
method is a method of the Object
class in Java that returns a string representation of the object. By default, the toString()
method returns a string that contains the name of the object’s class and its hash code. For example, if you create an instance of the Vehicle
class and call its toString()
method, you might get a string like this:
Vehicle@3b192d32
This string consists of the name of the class (Vehicle
) followed by the @
symbol and the hash code of the object in hexadecimal notation. This default implementation of toString()
is not very useful for debugging or logging, as it doesn’t provide any information about the state of the object.
However, you can override the toString()
method in your own classes to provide a more useful string representation of the object. For example, you might override toString()
in the Vehicle
class to return a string that contains information about the vehicle’s make, model, and year:
class Vehicle { private String make; private String model; private int year; public Vehicle(String make, String model, int year) { this.make = make; this.model = model; this.year = year; } @Override public String toString() { return year + " " + make + " " + model; } }
Now, if you create an instance of Vehicle
and call its toString()
method, you’ll get a string that contains information about the vehicle:
2010 Toyota Camry
The toString()
method is very useful for debugging and logging, as it allows you to quickly see the state of an object in a human-readable format. Many Java classes, such as collections and exceptions, override toString()
to provide useful string representations of their contents. When creating your own classes, you should always consider overriding toString()
to provide a useful string representation of the object’s state.
The equals()
Method
One of the most important methods inherited by Java classes from the Object
class is the equals()
method. The equals()
method is used to compare two objects for equality. By default, the equals()
method compares objects based on their memory addresses. This means that two objects will be considered equal only if they are the same instance of the same class.
For example:
String str1 = "hello"; String str2 = "hello"; String str3 = new String("hello"); System.out.println(str1.equals(str2)); // true System.out.println(str1.equals(str3)); // false
In the above example, str1
and str2
are both instances of the String
class and they contain the same value “hello”. Therefore, the equals()
method returns true
when comparing them. On the other hand, str3
is also an instance of the String
class and it contains the same value “hello”, but it is a different instance than str1
and str2
. Therefore, the equals()
method returns false
when comparing them.
Sometimes, we want to compare objects based on their content instead of their memory addresses. In such cases, we can override the equals()
method in our class to provide our own implementation for comparing objects. To override the equals()
method, we need to follow these rules:
- The
equals()
method must be public. - The
equals()
method must take anObject
parameter (i.e.,public boolean equals(Object obj)
). - The
equals()
method must return a boolean value (true
if the objects are equal,false
otherwise). - The
equals()
method must be consistent: if two objects are equal according to theequals()
method, then they must remain equal for the lifetime of the objects. - The
equals()
method must be reflexive: an object must be equal to itself. - The
equals()
method must be symmetric: ifa.equals(b)
returnstrue
, thenb.equals(a)
must also returntrue
. - The
equals()
method must be transitive: ifa.equals(b)
returnstrue
andb.equals(c)
returnstrue
, thena.equals(c)
must also returntrue
. - The
equals()
method must not throw an exception.
Here is an example of a class that overrides the equals()
method:
public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (!(obj instanceof Person)) { return false; } Person other = (Person) obj; return name.equals(other.name) && age == other.age; } }
In the above example, the equals()
method compares two Person
objects based on their name
and age
attributes.
The equals()
method VS the ==
operators
In Java, there are two ways to compare objects: using the equals()
method and the ==
operator. While both are used for comparison, they differ in their functionality.
The ==
operator is used to compare the references of two objects. It checks whether two objects are the same or not, i.e., if they refer to the same memory location. For example, if we have two objects obj1
and obj2
, obj1 == obj2
will return true
only if obj1
and obj2
refer to the same object in memory.
On the other hand, the equals()
method is used to compare the values of two objects. It checks whether two objects have the same values or not. By default, the equals()
method is inherited from the Object
class and compares the references of two objects. However, most classes override this method to compare the values of two objects.
When to use the ==
operator:
- Use the
==
operator when you want to check if two objects are the same instance. - Use the
==
operator when comparing primitive types.
When to use the equals()
method:
- Use the
equals()
method when you want to check if two objects have the same values. - Use the
equals()
method when comparing objects of non-primitive types.
It is important to note that not all classes override the equals()
method, and some may provide their own custom comparison methods. In such cases, it is important to understand the specific comparison logic provided by the class and use the appropriate method for comparison.
It is also important to note that when implementing the equals()
method, it is recommended to follow the guidelines laid out in the Java documentation to ensure consistency and correctness of the comparison logic.
The getClass()
Method
The getClass()
method is a non-static method of the Object
class that returns the runtime class of an object. The method is commonly used to determine the class of an object at runtime, which can be useful for a variety of purposes, such as debugging and logging.
Here’s an example that demonstrates how to use the getClass()
method to determine an object’s class:
Object obj = new String("Hello, world!"); Class<?> clazz = obj.getClass(); System.out.println("The class of obj is " + clazz.getName());
In this example, we create a new String
object and assign it to a variable of type Object
. We then use the getClass()
method to get the runtime class of the obj
variable, which is a String
. Finally, we print the name of the class using the getName()
method of the Class
class.
The output of this program will be:
The class of obj is java.lang.String
This example shows how the getClass()
method can be used to determine the class of an object at runtime. Note that the getClass()
method returns an object of type Class<?>
, which is a generic type that represents the runtime class of an object.
It’s worth noting that the getClass()
method is inherited by all classes in Java, so you can use it on any object to get its runtime class. However, the getClass()
method can be overridden by subclasses, so it’s possible that the method might not return the expected result in some cases.
Overall, the getClass()
method is a useful tool for determining the runtime class of an object, which can be useful for a variety of purposes.
The clone()
method
The clone()
method is a protected method defined in the Object
class that allows objects to be copied. The method creates a new object of the same class as the original object and initializes its fields with the same values as the original object.
Here’s an example of how to use the clone()
method:
class Person implements Cloneable { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (!(obj instanceof Person)) { return false; } Person other = (Person) obj; return this.name.equals(other.name) && this.age == other.age; } } class Main { public static void main(String[] args) throws CloneNotSupportedException { Person person1 = new Person("John", 25); Person person2 = (Person) person1.clone(); System.out.println(person1 == person2); // false System.out.println(person1.equals(person2)); // true } }
In this example, we create a Person
class that implements the Cloneable
interface. This is necessary because the clone()
method can only be called on objects that implement this interface.
Then we create an instance of Person
called person1
. We use the clone()
method to create a new instance of Person
called person2
. We cast the result of clone()
to the Person
class so that we can assign it to the person2
variable.
Finally, we compare the two instances of Person
. Since person1
and person2
are different objects (even though they have the same values for their fields), the comparison person1 == person2
returns false. However, since the Person
class overrides the equals()
method, the comparison person1.equals(person2)
returns true.
Note that the clone()
method creates a shallow copy of the object, meaning that any objects referenced by the original object are not duplicated. If you need a deep copy, you’ll need to implement it yourself.
Conclusion
In conclusion, the Object
class is an essential class in Java, as it serves as the ultimate parent class for all other classes. All classes in Java directly or indirectly inherit from the Object
class and inherit a set of useful methods such as toString()
, equals()
, getClass()
, clone()
, and more. By understanding these methods and how they are inherited, you can improve the quality and efficiency of your Java programs. Remember to always check the Java documentation for more information on these methods and how to use them effectively in your code.