🧬 Inheritance & Polymorphism · Intermediate

The Object class in Java

Root of all classes: equals, hashCode, toString, getClass, clone, wait/notify.

🧩 The mysteryYou've never written extends Object. Yet every object you create can call equals, hashCode and toString. Where did those methods come from?

The root of everything

java.lang.Object is the root of every class hierarchy. A class without extends silently extends Object, so every object — Strings, arrays, your own classes — has Object's methods.

class Pt { }
// really: class Pt extends Object { }

The universal toolkit

Object gives every object: **equals (logical equality), hashCode (an int for hash collections), toString (text), getClass (the runtime class — final, can't be overridden), clone, wait/notify/notifyAll** (thread signalling) and the deprecated finalize. The first three are meant to be overridden.

🔮 Predict it

Who are you, really?

What does this print?

Object o = 3.5;
String name = o.getClass().getSimpleName();
System.out.println(name);
  1. Object
  2. Double
  3. double
Show the answer

Double. The 3.5 was autoboxed into a Double object, and getClass() reports the real runtime class, whatever the variable's declared type.

🔮 Predict it

Two identical coins

Coin doesn't override equals. What prints?

class Coin { int value = 1; }
void main() {
    Coin a = new Coin(), b = new Coin();
    System.out.println(a.equals(b));
}
  1. true
  2. false
  3. Compile error
Show the answer

false. The inherited Object.equals is an identity check — true only for the very same object. Equal-looking fields don't matter until you override it.

⚠️ The trap

Not everything comes from Object

compareTo is not an Object method — it comes from the Comparable interface. Object declares equals, hashCode, toString, getClass, clone, wait, notify, notifyAll and finalize. Don't expect every object to be sortable.

💼 In the real world

In real projects

Because everything is an Object, collections, println and logging can work with any type. In practice you'll override equals, hashCode and toString constantly — or let records, IDEs and Lombok generate them for you.

Key takeaways

  1. Every class has Object as an ancestor
  2. equals/hashCode/toString are meant to be overridden
  3. getClass() returns the runtime class (final, can't override)
  4. wait/notify/notifyAll support low-level thread signalling
🤯 Did you know?

Object has no fields at all. The root of every class hierarchy carries no state of its own.

Practice questions

What does this print?

Object o = "text";
System.out.println(o.getClass().getSimpleName());
  1. Object
  2. String
  3. text
Check your answer

String. getClass() reports the object's real runtime class, String, whatever the variable's declared type.

What does this print?

class Pt { int x = 1; }
void main() {
    System.out.println(new Pt().equals(new Pt()));
}
  1. true
  2. false
  3. Compile error
Check your answer

false. Pt doesn't override equals, so it inherits Object's version, which only returns true for the very same object.

Next: overriding equals sounds easy — until you meet its five-rule contract.