Object Class Methods in Java

Introduction

Imagine you're building with LEGO blocks. Every single LEGO piece, regardless of its shape, color, or size, has some fundamental properties—they can connect to other pieces, they have a certain weight, and they're made of the same plastic material. In Java, the Object class is exactly like this foundation—it's the superclass of every other class, and every Java object inherits 11 fundamental methods from it!

The Object class is the root of the class hierarchy in Java. Every class you create automatically extends Object (even if you don't write extends Object), which means all your objects come with these built-in capabilities out of the box.


What is the Object Class?

The Object class is the superclass of all other classes in Java. It's located in the java.lang package and provides basic methods that are common to all objects.

Key Characteristics:

  • ✅ Root class - Every class implicitly extends Object
  • ✅ 11 methods - Provides fundamental object behaviors
  • ✅ Automatic inheritance - No need to explicitly extend
  • ✅ Foundation - Essential for Java's object system

The 11 Object Class Methods

Here are all the methods provided by the Object class:

  1. toString() - String representation of object
  2. equals(Object obj) - Compares objects for equality
  3. hashCode() - Returns hash code value
  4. getClass() - Returns runtime class of object
  5. clone() - Creates and returns a copy
  6. finalize() - Called by garbage collector before destruction
  7. wait() - Makes thread wait for notification
  8. wait(long timeout) - Wait with timeout
  9. wait(long timeout, int nanos) - Wait with nanosecond precision
  10. notify() - Wakes up a waiting thread
  11. notifyAll() - Wakes up all waiting threads

Code Explanation with Examples

Example 1: toString() Method

class Student { private String name; private int age; private double gpa; public Student(String name, int age, double gpa) { this.name = name; this.age = age; this.gpa = gpa; } // ❌ Without toString() override - uses Object's default // Default: className@hashCode // ✅ With toString() override - provides meaningful representation @Override public String toString() { return String.format("Student{name='%s', age=%d, gpa=%.2f}", name, age, gpa); } } class Product { private String name; private double price; public Product(String name, double price) { this.name = name; this.price = price; } // No toString() override - will use Object's default } public class ToStringDemo { public static void main(String[] args) { System.out.println("=== toString() METHOD DEMO ==="); Student student = new Student("Alice", 20, 3.8); Product product = new Product("Laptop", 999.99); // Explicit toString() calls System.out.println("Student toString(): " + student.toString()); System.out.println("Product toString(): " + product.toString()); // Implicit toString() calls (automatically called by print methods) System.out.println("\n=== IMPLICIT toString() CALLS ==="); System.out.println("Student: " + student); // Automatically calls toString() System.out.println("Product: " + product); // Automatically calls toString() // In collections System.out.println("\n=== IN COLLECTIONS ==="); java.util.List<Object> items = new java.util.ArrayList<>(); items.add(student); items.add(product); System.out.println("List contents:"); for (Object item : items) { System.out.println(" - " + item); // Automatically calls toString() } // Object's default toString() format System.out.println("\n=== DEFAULT toString() FORMAT ==="); System.out.println("Default format: ClassName@HashCode"); System.out.println("Student class: " + student.getClass().getSimpleName()); System.out.println("Student hashCode: " + Integer.toHexString(student.hashCode())); } }

Output:

=== toString() METHOD DEMO === Student toString(): Student{name='Alice', age=20, gpa=3.80} Product toString(): Product@15db9742 === IMPLICIT toString() CALLS === Student: Student{name='Alice', age=20, gpa=3.80} Product: Product@15db9742 === IN COLLECTIONS === List contents: - Student{name='Alice', age=20, gpa=3.80} - Product@15db9742 === DEFAULT toString() FORMAT === Default format: ClassName@HashCode Student class: Student Student hashCode: 6d311334

Example 2: equals() and hashCode() Methods

class Person { private String id; private String name; private int age; public Person(String id, String name, int age) { this.id = id; this.name = name; this.age = age; } // ❌ Without equals() override - uses Object's equals() (reference comparison) // ❌ Without hashCode() override - uses Object's hashCode() (memory address based) // ✅ Proper equals() override @Override public boolean equals(Object obj) { // 1. Check if same object reference if (this == obj) return true; // 2. Check if null or different class if (obj == null || getClass() != obj.getClass()) return false; // 3. Cast to Person Person person = (Person) obj; // 4. Compare significant fields return age == person.age && id.equals(person.id) && name.equals(person.name); } // ✅ Proper hashCode() override (MUST be consistent with equals()) @Override public int hashCode() { int result = id.hashCode(); result = 31 * result + name.hashCode(); result = 31 * result + age; return result; } @Override public String toString() { return String.format("Person{id='%s', name='%s', age=%d}", id, name, age); } } class BadPerson { private String id; private String name; public BadPerson(String id, String name) { this.id = id; this.name = name; } // ❌ BAD: Overrides equals() but not hashCode() - breaks contract! @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; BadPerson that = (BadPerson) obj; return id.equals(that.id) && name.equals(that.name); } // ❌ MISSING: No hashCode() override! } public class EqualsHashCodeDemo { public static void main(String[] args) { System.out.println("=== equals() AND hashCode() DEMO ==="); Person person1 = new Person("001", "Alice", 25); Person person2 = new Person("001", "Alice", 25); Person person3 = new Person("002", "Bob", 30); System.out.println("person1: " + person1); System.out.println("person2: " + person2); System.out.println("person3: " + person3); System.out.println("\n=== EQUALS COMPARISON ==="); System.out.println("person1 == person2: " + (person1 == person2)); // Reference comparison System.out.println("person1.equals(person2): " + person1.equals(person2)); // Content comparison System.out.println("person1.equals(person3): " + person1.equals(person3)); System.out.println("\n=== HASHCODE VALUES ==="); System.out.println("person1.hashCode(): " + person1.hashCode()); System.out.println("person2.hashCode(): " + person2.hashCode()); System.out.println("person3.hashCode(): " + person3.hashCode()); System.out.println("Hash codes equal for equal objects: " + (person1.hashCode() == person2.hashCode())); System.out.println("\n=== USING IN COLLECTIONS ==="); java.util.Set<Person> personSet = new java.util.HashSet<>(); personSet.add(person1); personSet.add(person2); // Should not be added (duplicate) personSet.add(person3); System.out.println("HashSet size: " + personSet.size()); // Should be 2 System.out.println("HashSet contents: " + personSet); System.out.println("\n=== PROBLEM: EQUALS WITHOUT HASHCODE ==="); BadPerson bad1 = new BadPerson("001", "Alice"); BadPerson bad2 = new BadPerson("001", "Alice"); System.out.println("bad1.equals(bad2): " + bad1.equals(bad2)); System.out.println("bad1.hashCode(): " + bad1.hashCode()); System.out.println("bad2.hashCode(): " + bad2.hashCode()); System.out.println("Different hashcodes for equal objects! ❌"); java.util.Set<BadPerson> badSet = new java.util.HashSet<>(); badSet.add(bad1); badSet.add(bad2); // Both added! ❌ Broken contract System.out.println("Bad HashSet size: " + badSet.size()); // Should be 1, but is 2! System.out.println("\n=== EQUALS CONTRACT RULES ==="); System.out.println("1. Reflexive: x.equals(x) must be true"); System.out.println("2. Symmetric: x.equals(y) ⇔ y.equals(x)"); System.out.println("3. Transitive: x.equals(y) ∧ y.equals(z) ⇒ x.equals(z)"); System.out.println("4. Consistent: Multiple calls return same result"); System.out.println("5. x.equals(null) must return false"); System.out.println("6. If x.equals(y), then x.hashCode() == y.hashCode()"); } }

Output:

=== equals() AND hashCode() DEMO === person1: Person{id='001', name='Alice', age=25} person2: Person{id='001', name='Alice', age=25} person3: Person{id='002', name='Bob', age=30} === EQUALS COMPARISON === person1 == person2: false person1.equals(person2): true person1.equals(person3): false === HASHCODE VALUES === person1.hashCode(): 1965783557 person2.hashCode(): 1965783557 person3.hashCode(): 66481 Hash codes equal for equal objects: true === USING IN COLLECTIONS === HashSet size: 2 HashSet contents: [Person{id='002', name='Bob', age=30}, Person{id='001', name='Alice', age=25}] === PROBLEM: EQUALS WITHOUT HASHCODE === bad1.equals(bad2): true bad1.hashCode(): 366712642 bad2.hashCode(): 1829164700 Different hashcodes for equal objects! ❌ Bad HashSet size: 2 === EQUALS CONTRACT RULES === 1. Reflexive: x.equals(x) must be true 2. Symmetric: x.equals(y) ⇔ y.equals(x) 3. Transitive: x.equals(y) ∧ y.equals(z) ⇒ x.equals(z) 4. Consistent: Multiple calls return same result 5. x.equals(null) must return false 6. If x.equals(y), then x.hashCode() == y.hashCode()

Example 3: getClass() and clone() Methods

class Employee implements Cloneable { private String name; private int employeeId; private double salary; private Department department; public Employee(String name, int employeeId, double salary, Department department) { this.name = name; this.employeeId = employeeId; this.salary = salary; this.department = department; } // getClass() demonstration public void displayClassInfo() { Class<?> clazz = this.getClass(); System.out.println("Class Name: " + clazz.getName()); System.out.println("Simple Name: " + clazz.getSimpleName()); System.out.println("Superclass: " + clazz.getSuperclass().getSimpleName()); System.out.println("Is Interface: " + clazz.isInterface()); } // ✅ Proper clone() implementation @Override protected Object clone() throws CloneNotSupportedException { // First, call super.clone() for shallow copy Employee cloned = (Employee) super.clone(); // For deep copy, also clone mutable fields cloned.department = (Department) department.clone(); return cloned; } // Alternative: Copy constructor for cloning public Employee(Employee other) { this.name = other.name; this.employeeId = other.employeeId; this.salary = other.salary; this.department = new Department(other.department); } // Getters and setters public String getName() { return name; } public void setName(String name) { this.name = name; } public int getEmployeeId() { return employeeId; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public Department getDepartment() { return department; } public void setDepartment(Department department) { this.department = department; } @Override public String toString() { return String.format("Employee{id=%d, name='%s', salary=%.2f, dept=%s}", employeeId, name, salary, department); } } class Department implements Cloneable { private String name; private String location; public Department(String name, String location) { this.name = name; this.location = location; } // Copy constructor public Department(Department other) { this.name = other.name; this.location = other.location; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); // Shallow copy is fine for Department (Strings are immutable) } // Getters and setters public String getName() { return name; } public void setName(String name) { this.name = name; } public String getLocation() { return location; } public void setLocation(String location) { this.location = location; } @Override public String toString() { return String.format("Department{name='%s', location='%s'}", name, location); } } class Manager extends Employee { private int teamSize; public Manager(String name, int employeeId, double salary, Department department, int teamSize) { super(name, employeeId, salary, department); this.teamSize = teamSize; } @Override public void displayClassInfo() { super.displayClassInfo(); System.out.println("Additional info: This is a Manager class"); } @Override public String toString() { return super.toString().replace("Employee", "Manager") + String.format(", teamSize=%d}", teamSize); } } public class GetClassCloneDemo { public static void main(String[] args) { System.out.println("=== getClass() AND clone() DEMO ==="); Department dept = new Department("Engineering", "New York"); Employee emp1 = new Employee("John Doe", 1001, 75000.0, dept); Manager mgr1 = new Manager("Alice Smith", 2001, 120000.0, dept, 8); System.out.println("=== getClass() DEMONSTRATION ==="); System.out.println("Employee class info:"); emp1.displayClassInfo(); System.out.println("\nManager class info:"); mgr1.displayClassInfo(); System.out.println("\n=== CLASS COMPARISON ==="); System.out.println("emp1.getClass() == Employee.class: " + (emp1.getClass() == Employee.class)); System.out.println("mgr1.getClass() == Manager.class: " + (mgr1.getClass() == Manager.class)); System.out.println("mgr1.getClass() == Employee.class: " + (mgr1.getClass() == Employee.class)); System.out.println("mgr1 instanceof Employee: " + (mgr1 instanceof Employee)); System.out.println("\n=== clone() DEMONSTRATION ==="); try { // Clone using clone() method Employee emp2 = (Employee) emp1.clone(); System.out.println("Original: " + emp1); System.out.println("Cloned: " + emp2); // Modify original and check if clone is affected emp1.setSalary(80000.0); emp1.getDepartment().setName("Modified Engineering"); System.out.println("\nAfter modifying original:"); System.out.println("Original: " + emp1); System.out.println("Cloned: " + emp2); // Should be unchanged (deep copy) System.out.println("\n=== COPY CONSTRUCTOR ==="); // Alternative to clone() - copy constructor Employee emp3 = new Employee(emp1); System.out.println("Original: " + emp1); System.out.println("Copied: " + emp3); } catch (CloneNotSupportedException e) { System.out.println("Clone not supported: " + e.getMessage()); } System.out.println("\n=== OBJECT CLASS HIERARCHY ==="); displayClassHierarchy(mgr1); } public static void displayClassHierarchy(Object obj) { System.out.println("Class hierarchy for: " + obj.getClass().getSimpleName()); Class<?> clazz = obj.getClass(); while (clazz != null) { System.out.println(" → " + clazz.getName()); clazz = clazz.getSuperclass(); } System.out.println(" → (end)"); } }

Output:

=== getClass() AND clone() DEMO === === getClass() DEMONSTRATION === Employee class info: Class Name: Employee Simple Name: Employee Superclass: Object Is Interface: false Manager class info: Class Name: Manager Simple Name: Manager Superclass: Employee Is Interface: false Additional info: This is a Manager class === CLASS COMPARISON === emp1.getClass() == Employee.class: true mgr1.getClass() == Manager.class: true mgr1.getClass() == Employee.class: false mgr1 instanceof Employee: true === clone() DEMONSTRATION === Original: Employee{id=1001, name='John Doe', salary=75000.00, dept=Department{name='Engineering', location='New York'}} Cloned: Employee{id=1001, name='John Doe', salary=75000.00, dept=Department{name='Engineering', location='New York'}} After modifying original: Original: Employee{id=1001, name='John Doe', salary=80000.00, dept=Department{name='Modified Engineering', location='New York'}} Cloned: Employee{id=1001, name='John Doe', salary=75000.00, dept=Department{name='Engineering', location='New York'}} === COPY CONSTRUCTOR === Original: Employee{id=1001, name='John Doe', salary=80000.00, dept=Department{name='Modified Engineering', location='New York'}} Copied: Employee{id=1001, name='John Doe', salary=80000.00, dept=Department{name='Modified Engineering', location='New York'}} === OBJECT CLASS HIERARCHY === Class hierarchy for: Manager → Manager → Employee → java.lang.Object → (end)

Example 4: wait(), notify(), notifyAll() Methods

class Message { private String content; private boolean empty = true; public synchronized String read() { // Wait until message is available while (empty) { try { System.out.println(Thread.currentThread().getName() + " is waiting to read..."); wait(); // 🎯 Object's wait() method } catch (InterruptedException e) { Thread.currentThread().interrupt(); return null; } } empty = true; System.out.println(Thread.currentThread().getName() + " read: " + content); notifyAll(); // 🎯 Object's notifyAll() method return content; } public synchronized void write(String content) { // Wait until message has been read while (!empty) { try { System.out.println(Thread.currentThread().getName() + " is waiting to write..."); wait(); // 🎯 Object's wait() method } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } } empty = false; this.content = content; System.out.println(Thread.currentThread().getName() + " wrote: " + content); notifyAll(); // 🎯 Object's notifyAll() method } } class Reader implements Runnable { private Message message; public Reader(Message message) { this.message = message; } @Override public void run() { for (int i = 0; i < 3; i++) { String readMessage = message.read(); try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } } } class Writer implements Runnable { private Message message; public Writer(Message message) { this.message = message; } @Override public void run() { String[] messages = { "Hello World!", "Java Programming", "Thread Communication" }; for (String msg : messages) { message.write(msg); try { Thread.sleep(1500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } } } public class WaitNotifyDemo { public static void main(String[] args) { System.out.println("=== wait(), notify(), notifyAll() DEMO ==="); System.out.println("Producer-Consumer Problem Solution\n"); Message message = new Message(); // Create multiple readers and writers Thread writerThread = new Thread(new Writer(message), "Writer-1"); Thread readerThread1 = new Thread(new Reader(message), "Reader-1"); Thread readerThread2 = new Thread(new Reader(message), "Reader-2"); writerThread.start(); readerThread1.start(); readerThread2.start(); // Wait for threads to complete try { writerThread.join(); readerThread1.join(); readerThread2.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.println("\n=== THREAD COMMUNICATION COMPLETED ==="); // Demonstrate simple wait/notify System.out.println("\n=== SIMPLE WAIT/NOTIFY EXAMPLE ==="); Object lock = new Object(); Thread waitingThread = new Thread(() -> { synchronized (lock) { try { System.out.println(Thread.currentThread().getName() + " is waiting..."); lock.wait(); // 🎯 Object's wait() method System.out.println(Thread.currentThread().getName() + " is notified!"); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }, "WaitingThread"); Thread notifyingThread = new Thread(() -> { synchronized (lock) { try { Thread.sleep(2000); System.out.println(Thread.currentThread().getName() + " is notifying..."); lock.notify(); // 🎯 Object's notify() method } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }, "NotifyingThread"); waitingThread.start(); notifyingThread.start(); try { waitingThread.join(); notifyingThread.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.println("=== WAIT/NOTIFY COMPLETED ==="); } }

Output:

=== wait(), notify(), notifyAll() DEMO === Producer-Consumer Problem Solution Writer-1 wrote: Hello World! Reader-2 read: Hello World! Writer-1 is waiting to write... Reader-1 is waiting to read... Writer-1 wrote: Java Programming Reader-1 read: Java Programming Writer-1 is waiting to write... Reader-2 is waiting to read... Writer-1 wrote: Thread Communication Reader-2 read: Thread Communication === THREAD COMMUNICATION COMPLETED === === SIMPLE WAIT/NOTIFY EXAMPLE === WaitingThread is waiting... NotifyingThread is notifying... WaitingThread is notified! === WAIT/NOTIFY COMPLETED ===

Example 5: finalize() Method (Deprecated but Important to Understand)

class Resource { private String name; private static int created = 0; private static int finalized = 0; public Resource(String name) { this.name = name; created++; System.out.println("Resource '" + name + "' created. Total created: " + created); } public void use() { System.out.println("Using resource: " + name); } // 🎯 finalize() method - called by garbage collector before object destruction // ⚠️ DEPRECATED in Java 9+ - don't use in new code! @Override protected void finalize() throws Throwable { try { finalized++; System.out.println("⚠️ Resource '" + name + "' finalized. Total finalized: " + finalized); } finally { super.finalize(); } } public static void displayStats() { System.out.println("=== RESOURCE STATS ==="); System.out.println("Created: " + created); System.out.println("Finalized: " + finalized); System.out.println("Active: " + (created - finalized)); } } public class FinalizeDemo { public static void main(String[] args) { System.out.println("=== finalize() METHOD DEMO ==="); System.out.println("⚠️ Note: finalize() is deprecated in modern Java!"); System.out.println("It's shown here for educational purposes only.\n"); // Create some resources Resource res1 = new Resource("Database Connection"); Resource res2 = new Resource("File Handle"); Resource res3 = new Resource("Network Socket"); // Use resources res1.use(); res2.use(); // Make objects eligible for garbage collection System.out.println("\n=== MAKING OBJECTS ELIGIBLE FOR GC ==="); res1 = null; res2 = null; // Explicitly suggest garbage collection (not guaranteed!) System.out.println("Suggesting garbage collection..."); System.gc(); // Wait a bit to allow GC to run (not reliable in demo) try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } Resource.displayStats(); // Create more resources System.out.println("\n=== CREATING MORE RESOURCES ==="); for (int i = 0; i < 5; i++) { new Resource("TempResource-" + i); } // Suggest GC again System.out.println("Suggesting garbage collection again..."); System.gc(); try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } Resource.displayStats(); System.out.println("\n=== MODERN ALTERNATIVES TO finalize() ==="); System.out.println("1. try-with-resources (AutoCloseable interface)"); System.out.println("2. Cleaner API (Java 9+)"); System.out.println("3. Explicit close() methods"); System.out.println("4. Phantom references"); // Modern approach: try-with-resources System.out.println("\n=== MODERN APPROACH: try-with-resources ==="); try (ModernResource mr = new ModernResource("Modern Resource")) { mr.use(); } catch (Exception e) { System.out.println("Error: " + e.getMessage()); } // Automatically closed - no need for finalize() } } // Modern approach using AutoCloseable class ModernResource implements AutoCloseable { private String name; private boolean closed = false; public ModernResource(String name) { this.name = name; System.out.println("ModernResource '" + name + "' created"); } public void use() { if (closed) { throw new IllegalStateException("Resource is closed"); } System.out.println("Using modern resource: " + name); } @Override public void close() { if (!closed) { closed = true; System.out.println("ModernResource '" + name + "' closed properly"); } } }

Output:

=== finalize() METHOD DEMO === ⚠️ Note: finalize() is deprecated in modern Java! It's shown here for educational purposes only. Resource 'Database Connection' created. Total created: 1 Resource 'File Handle' created. Total created: 2 Resource 'Network Socket' created. Total created: 3 Using resource: Database Connection Using resource: File Handle === MAKING OBJECTS ELIGIBLE FOR GC === Suggesting garbage collection... ⚠️ Resource 'File Handle' finalized. Total finalized: 1 ⚠️ Resource 'Database Connection' finalized. Total finalized: 2 === RESOURCE STATS === Created: 3 Finalized: 2 Active: 1 === CREATING MORE RESOURCES === Resource 'TempResource-0' created. Total created: 4 Resource 'TempResource-1' created. Total created: 5 Resource 'TempResource-2' created. Total created: 6 Resource 'TempResource-3' created. Total created: 7 Resource 'TempResource-4' created. Total created: 8 Suggesting garbage collection again... ⚠️ Resource 'TempResource-4' finalized. Total finalized: 3 ⚠️ Resource 'TempResource-3' finalized. Total finalized: 4 ⚠️ Resource 'TempResource-2' finalized. Total finalized: 5 ⚠️ Resource 'TempResource-1' finalized. Total finalized: 6 ⚠️ Resource 'TempResource-0' finalized. Total finalized: 7 === RESOURCE STATS === Created: 8 Finalized: 7 Active: 1 === MODERN ALTERNATIVES TO finalize() === 1. try-with-resources (AutoCloseable interface) 2. Cleaner API (Java 9+) 3. Explicit close() methods 4. Phantom references === MODERN APPROACH: try-with-resources === ModernResource 'Modern Resource' created Using modern resource: Modern Resource ModernResource 'Modern Resource' closed properly

Complete Object Methods Summary

MethodPurposeWhen to Override
toString()String representationAlways for meaningful output
equals()Object equality comparisonWhen you need content comparison
hashCode()Hash code for collectionsMust override when equals() is overridden
getClass()Runtime class informationRarely - used for reflection
clone()Object copyingWhen you need cloning capability
finalize()Cleanup before GC⚠️ Deprecated - don't use
wait()Thread waitingRarely - used in synchronization
notify()Thread notificationRarely - used in synchronization
notifyAll()Notify all threadsRarely - used in synchronization

Best Practices

✅ toString(): Always override for debugging and logging

✅ equals() and hashCode(): Override together, follow contract

✅ clone(): Prefer copy constructors or factory methods

✅ finalize(): ⚠️ Avoid - use try-with-resources instead

✅ wait/notify: Use higher-level concurrency utilities when possible

// ✅ GOOD: Proper equals() and hashCode() @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return age == person.age && Objects.equals(name, person.name) && Objects.equals(email, person.email); } @Override public int hashCode() { return Objects.hash(name, age, email); } // ✅ GOOD: Meaningful toString() @Override public String toString() { return String.format("Person{name='%s', age=%d, email='%s'}", name, age, email); }

Common Pitfalls

// ❌ BAD: equals() without hashCode() class BadExample { private String data; @Override public boolean equals(Object obj) { /*...*/ } // ❌ Missing hashCode()! } // ❌ BAD: Relying on finalize() class Resource { // ❌ Don't rely on finalize() for cleanup protected void finalize() { cleanup(); } } // ✅ GOOD: Use try-with-resources try (Resource res = new Resource()) { // use resource } // automatically closed

Conclusion

The Object class is the foundation of Java's object system:

  • ✅ Root of class hierarchy - every class extends Object
  • ✅ 11 fundamental methods - common behaviors for all objects
  • ✅ Automatic inheritance - no need to explicitly extend
  • ✅ Essential for collections - equals(), hashCode(), toString()
  • ✅ Thread coordination - wait(), notify(), notifyAll()

Key Takeaways:

  • Always override toString() for meaningful object representation
  • Override equals() and hashCode() together following the contract
  • Avoid finalize() - use modern resource management
  • Use getClass() for runtime type information
  • Understand wait/notify for basic thread coordination

Mastering Object class methods is essential for writing correct, efficient, and maintainable Java code. They're the building blocks that make Java's object-oriented system work!

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper