Java Object Class
Methods every Java object inherits from java.lang.Object — toString, equals, hashCode, getClass, clone, and finalize.
Every class in Java — whether you write extends Object or not — sits beneath java.lang.Object in the type hierarchy. That means every reference you ever hold has a small bundle of methods available on it: toString, equals, hashCode, getClass, and a few more. Understanding what they do by default, and when you should override them, is the difference between objects that play nicely with collections, debuggers, and frameworks — and objects that don't.
This chapter is the map of the territory. The next few chapters drill into the specific methods (equals/hashCode, toString, clone) one at a time.
Implicit extension
Write a class with no extends clause:
public class Box {
int contents;
}The compiler treats it as if you'd written public class Box extends Object. That's why you can hand a Box to anything declared as Object — every reference type ultimately is an Object.
The inherited methods at a glance
| Method | What the default does |
|---|---|
toString() | Returns ClassName@hashCodeHex — almost never what you want |
equals(Object) | Reference equality (==) |
hashCode() | A value derived from the object's identity, not its contents |
getClass() | The runtime Class<?> token — never null |
clone() | A shallow field-by-field copy, but only on classes that implement Cloneable; otherwise throws |
wait(), notify(), notifyAll() | Low-level monitor primitives used with synchronized |
finalize() | Hook called by the GC before reclaiming an object — deprecated, do not use |
The first three are the ones almost every domain class should override. getClass you call on objects. The threading primitives you rarely touch directly. clone and finalize are best avoided in modern code (clone gets its own chapter; finalize is replaced by try-with-resources and Cleaner).
toString — the default is unhelpful
The inherited toString returns something like Box@1540e19d. That's the class name and the identity hash code in hex — useless for logging, debugging, or any kind of diagnostics:
Box b = new Box();
System.out.println(b); // Box@1540e19dOverride it to return something readable. The next chapter walks through doing this well.
equals and hashCode — they go together
The inherited equals only returns true when both references point to the same object:
String a = new String("hi");
String b = new String("hi");
System.out.println(a == b); // false — different objects
System.out.println(a.equals(b)); // true — String overrides equalsString overrides equals to compare contents. A class you write does not, unless you override it yourself. And the moment you override equals, you must also override hashCode — otherwise your objects will silently misbehave in HashSet and HashMap. The chapter on equals and hashCode covers the exact rules.
getClass — the runtime type token
getClass() returns the Class<?> object describing the runtime type:
Object o = "hello";
System.out.println(o.getClass().getName()); // java.lang.StringIt's used inside reflective code, by equals implementations that want exact-type comparisons, and by debugging output. Note that getClass() is final — you can't override it.
clone and Cloneable
Object.clone() is protected and only succeeds on classes that explicitly declare implements Cloneable. The result is a shallow copy: a new instance with the same field values, including the same references to mutable sub-objects. It's a notoriously awkward API, covered in detail in the cloning chapter.
wait / notify
These methods, plus notifyAll, are part of Java's original low-level concurrency primitives. They're tied to synchronized blocks and used to build wait-for-condition patterns. In modern code, prefer the higher-level utilities in java.util.concurrent (locks, BlockingQueue, CompletableFuture); raw wait/notify is rare outside library internals.
finalize — leave it alone
finalize() was once the GC's way to give your object a last chance to release resources. It's been deprecated since Java 9 and removed in newer releases. Use try-with-resources for I/O and java.lang.ref.Cleaner for the very rare case where you must run code after collection.
A worked example
What's next
The single most common — and most error-prone — override of an Object method is equals paired with hashCode. The next chapter walks through the contract both methods have to honor and the patterns for getting it right. Continue to Java equals and hashCode.
Practice
What does the default `toString()` inherited from `Object` return?