"Java's Object Class: The Bedrock of OOP"
In Java, the Object
class is the cornerstone of Object Oriented Programming (OOP). It offers key methods that facilitate key OOP principles such as inheritance, polymorphism, and encapsulation. This blog will take you on a deep dive into the Object
class, examining its methods and demonstrating best practices for using them effectively in your projects.
INTRODUCTION
In Java, the Object class is the root class in the class hierarchy. Every class in Java directly or indirectly inherits the Object class. This means that all classes in Java inherit the methods of the Object
class.
KEY POINTS
The root of the Class Hierarchy: All classes(predefined or user-defined) in Java inherit from
Object
class.Common Methods: The
Object
class defines several methods that are inherited by all classes.
Common Methods of theObject
Class
Let's understand each method in detail
toString()
// default implementation
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
Its primary purpose is to provide a string representation of an object. This method is often overridden in classes to return a more meaningful string that represents the object's state.
Consider the example:
class Bike {
private String make;
private double price;
public Bike(String make, double price) {
this.make = make;
this.price = price;
}
public String toString() {
return "Make is " + this.make + " and price is " + this.price;
}
}
public class ObjectClassEx {
public static void main(String[] args) {
Bike splendorBike = new Bike("Hero", 90000.00);
System.out.println(splendorBike);
// Output after overriding toString()
// Make is Hero and price is 90000.0
// Output without overriding toString()
// Bike@5acf9800
}
}
NOTE: When we try to print object reference, internally the toString() method is called.
getClass()
: The getClass() method returns the class to which the object belongs.
Consider this example
class Bike {
private String make;
private double price;
public Bike(String make, double price) {
this.make = make;
this.price = price;
}
}
public class ObjectClassEx {
public static void main(String[] args) {
Bike splendorBike = new Bike("Hero", 90000.00);
System.out.println(splendorBike.getClass());
// output
// class Bike
}
}
equals()
: Theequals()
of Object class method is used to check whether the two objects are equal. It returnstrue
if the references of the two objects being compared point to the same object in memory.
// default implementation
public boolean equals(Object obj) {
return (this == obj);
}
Consider this example
class Bike {
private String make;
private double price;
public Bike(String make, double price) {
this.make = make;
this.price = price;
}
}
public class ObjectClassEx {
public static void main(String[] args) {
Bike splendorBike = new Bike("Hero", 90000.00);
Bike bulletBike = new Bike("RE", 200000.0);
System.out.println(splendorBike.equals(bulletBike));
// Output
// false
}
}
- To provide a more meaningful comparison between the two objects we often override the
equals()
method.
Consider the example
class Bike {
private String make;
private double price;
public Bike(String make, double price) {
this.make = make;
this.price = price;
}
public boolean equals(Object object) {
Bike bike = (Bike) object;
if (this.make == bike.make && this.price == bike.price) {
return true;
} else {
return false;
}
}
}
public class ObjectClassEx {
public static void main(String[] args) {
Bike splendorBike1 = new Bike("Hero", 90000.00);
Bike splendorBike2 = new Bike("Hero", 90000.00);
Bike bulletBike = new Bike("RE", 200000.0);
System.out.println(splendorBike1.equals(splendorBike2)); // true
System.out.println(splendorBike1.equals(bulletBike)); // false
}
}
- The above code example will check the equality of the two objects based on their values rather than their reference.
It is necessary to override hashcode()
method when we override the equals() method so as to provide the same hashcode to the equal object
hashcode()
: Thehashcode()
method returns a unique integer hashcode value for an object.
- Default Implementation: Its default implementation is that it converts the address of an object to the integer value i.e. hashcode.
Consider the code example forhashcode()
method:
import java.util.Objects;
class Bike {
private String make;
private double price;
public Bike(String make, double price) {
this.make = make;
this.price = price;
}
public boolean equals(Object object) {
Bike bike = (Bike) object;
if (this.make == bike.make && this.price == bike.price) {
return true;
} else {
return false;
}
}
public int hashCode() {
return Objects.hash(make, price);
}
}
public class ObjectClassEx {
public static void main(String[] args) {
Bike splendorBike1 = new Bike("Hero", 90000.00);
Bike splendorBike2 = new Bike("Hero", 90000.00);
Bike splendorBike3 = new Bike("HeroHonda", 95000.00);
System.out.println(splendorBike1.hashCode()); // 1159478247
System.out.println(splendorBike2.hashCode()); // 1159478247
System.out.println(splendorBike3.hashCode()); // 1235333554
System.out.println(splendorBike1.equals(splendorBike2)); // true
System.out.println(splendorBike1.equals(splendorBike3)); // false
}
}
clone()
: Theclone()
method is used to create and return a copy (clone) of the object on which it is called.
Consider the code example
class Car implements Cloneable {
String make;
double price;
public Car (String make, double price) {
this.make = make;
this.price = price;
}
@Override
public Object clone () throws CloneNotSupportedException {
return super.clone();
}
}
public class ObjectClassEx {
public static void main(String[] args) throws CloneNotSupportedException {
Car civic1 = new Car("Honda", 80000.00);
Car civic2 = (Car)civic1.clone();
System.out.println(civic1.make);
System.out.println(civic2.make);
}
}
In the above code example, the civic1
object is shallowly copied into civic2
object.
finalize()
: Thefinalize()
method is called by the garbage collector before an object is destroyed. It is intended to allow the object to clean up resources before it is reclaimed. However, its use is generally discouraged due to unpredictability and performance issues and is deprecated. We use other resource management techniques such as try-with-resource etc.
Note on Thread Methods: wait()
, notify()
, and notifyAll()
The Object
class also includes the wait()
, notify()
, and notifyAll()
methods, which are essential for thread synchronization and inter-thread communication. These methods allow threads to communicate about the availability of resources and synchronize their actions.
However, these methods are complex and involve detailed concepts related to threading and concurrency. Therefore, we will cover them comprehensively in another blog dedicated to threads and inter-thread communication. Stay tuned for an in-depth discussion on these crucial methods, along with practical examples and best practices for using them in multi-threaded applications.
Conclusion
Stay tuned for our upcoming blogs where we dive deeper into advanced topics like thread communication and synchronization. Happy coding!
Subscribe to my newsletter
Read articles from Vivan Kumar directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Vivan Kumar
Vivan Kumar
Tech Enthusiast