Definition
java.lang.Object has 11 methods that every Java class inherits.
- getClass(): returns the runtime
Class>object. Useful for reflection, logging, and exact type checking (getClass() == SavingsAccount.classchecks exact type, unlikeinstanceofwhich includes subclasses). - clone(): creates a shallow copy. Requires the
Cloneablemarker interface. ReturnsObject(must cast). Discouraged: prefer copy constructors. - wait() / notify() / notifyAll(): inter-thread communication using the object's intrinsic monitor lock.
wait()releases the lock and suspends the thread.notify()wakes one waiting thread. Must be called insidesynchronizedbecause they manipulate the monitor lock: without the lock,IllegalMonitorStateException. - finalize(): called by GC before reclaiming the object. Deprecated since Java 9: unreliable, slow, can resurrect objects. Use
AutoCloseable+ try-with-resources orCleanerinstead.
getClass() is like checking which type of account this is at runtime. clone() is photocopying the account file (shallow: shared address card). wait/notify is the producer-consumer pattern: the teller (producer) says next customer, please (notify). The customer (consumer) says I will wait until called (wait). Both must hold the same ticket counter lock (synchronized). finalize() is the old janitor who cleaned up after closing hours: retired (deprecated). Use the new cleaning service (Cleaner/try-with-resources).
Understanding the Concepts
What do the Object methods beyond equals/hashCode do?
Every Java class inherits 11 methods from Object. Beyond equals/hashCode/toString, four important groups exist.
What does getClass() do?
Account ref = new SavingsAccount("SAV001", java.math.BigDecimal.ZERO);
Class<?> cls = ref.getClass();
cls.getName(); // "com.bank.SavingsAccount" (actual type, not variable type)
cls.getSimpleName(); // "SavingsAccount"
cls.getSuperclass(); // Account.class
// Exact type check (no subclasses):
if (ref.getClass() == SavingsAccount.class) { /* exact match only */ }
// vs instanceof (includes subclasses):
if (ref instanceof Account) { /* SavingsAccount passes too */ }
// getClass() is final: cannot be overridden.
What does clone() do?
public class Trade implements Cloneable {
@Override
public Trade clone() {
try {
return (Trade) super.clone(); // shallow copy
} catch (CloneNotSupportedException e) {
throw new AssertionError(); // never happens: we implement Cloneable
}
}
}
// clone() is protected on Object: must override as public.
// Without Cloneable: CloneNotSupportedException.
// Discouraged: prefer copy constructors or records.
What do wait/notify/notifyAll do?
public class TradeQueue {
private final java.util.Queue<Trade> queue = new java.util.LinkedList<>();
private static final int MAX = 10;
public synchronized void produce(Trade trade) throws InterruptedException {
while (queue.size() == MAX) {
wait(); // queue full: release lock, suspend this thread
}
queue.add(trade);
notifyAll(); // wake up all waiting consumers
}
public synchronized Trade consume() throws InterruptedException {
while (queue.isEmpty()) {
wait(); // queue empty: release lock, suspend this thread
}
Trade trade = queue.poll();
notifyAll(); // wake up all waiting producers
return trade;
}
}
// Why synchronized is required:
// wait() releases the object's monitor lock. If you do not hold the lock, there is nothing to release.
// Without synchronized: IllegalMonitorStateException at runtime.
Why is finalize() deprecated?
// OLD (deprecated since Java 9):
@Override
protected void finalize() throws Throwable {
closeConnection(); // unreliable: no guarantee when or if GC calls this
}
// NEW: use AutoCloseable + try-with-resources
public class DbConnection implements AutoCloseable {
@Override
public void close() {
connection.close(); // deterministic cleanup
}
}
try (var conn = new DbConnection()) {
// use conn
} // close() called automatically, always
How do all Object methods compare?
| Method | Purpose | Can override? | Notes |
|--------|---------|--------------|-------|
| equals() | Value equality | Yes | Override with hashCode |
| hashCode() | Hash code for collections | Yes | Must be consistent with equals |
| toString() | String representation | Yes | Used by println, debugger |
| getClass() | Runtime type info | No (final) | Returns Class> |
| clone() | Shallow copy | Yes | Requires Cloneable |
| wait() | Thread waits for notify | No (final) | Must be in synchronized |
| notify() | Wakes one waiting thread | No (final) | Must be in synchronized |
| notifyAll() | Wakes all waiting threads | No (final) | Must be in synchronized |
| finalize() | GC cleanup | Yes | Deprecated since Java 9 |
What are common mistakes?
The most common mistake is calling wait() or notify() outside a synchronized block.
// WRONG: not in synchronized
// trade.wait(); // IllegalMonitorStateException
// CORRECT: inside synchronized
synchronized(trade) { trade.wait(); }
What should a senior engineer know?
- Modern concurrency uses java.util.concurrent (BlockingQueue, CountDownLatch, CompletableFuture) instead of raw wait/notify.
- finalize() has been replaced by Cleaner (Java 9) and PhantomReference for GC-triggered cleanup.
- getClass() is used in correct equals() implementations to prevent symmetry violations in inheritance hierarchies.
Visual Overview
java.lang.Object (11 methods) ┌─────────────────────────────────────────┐ │ IDENTITY & EQUALITY │ │ equals(Object) hashCode() toString() │ ├─────────────────────────────────────────┤ │ TYPE INFORMATION │ │ getClass() [final, cannot override] │ ├─────────────────────────────────────────┤ │ COPYING │ │ clone() [needs Cloneable marker] │ ├─────────────────────────────────────────┤ │ THREAD COMMUNICATION │ │ wait() notify() notifyAll() │ │ [all final, must be in synchronized] │ ├─────────────────────────────────────────┤ │ CLEANUP (deprecated) │ │ finalize() [use Cleaner instead] │ └─────────────────────────────────────────┘
Key Takeaway
Every Java class inherits 11 methods from Object. Beyond equals/hashCode/toString: getClass() returns the runtime Class object for reflection and exact type checking. clone() creates a shallow copy requiring the Cloneable marker: discouraged in favor of copy constructors. wait/notify/notifyAll enable inter-thread communication: wait releases the object's monitor lock and suspends the thread; notify wakes one waiting thread. They must be called inside synchronized because wait releases the monitor lock and you must hold it first. Without synchronized: IllegalMonitorStateException. finalize() is deprecated since Java 9: use AutoCloseable with try-with-resources for deterministic cleanup.
Remember one sentence: every class inherits 11 methods from Object, and the key rules are that wait/notify must be in synchronized, clone needs Cloneable, getClass is final, and finalize is deprecated in favor of try-with-resources.
---