W3docs

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

MethodWhat 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@1540e19d

Override 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 equals

String 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.String

It'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

java— editable, runs on the server

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

Practice

What does the default `toString()` inherited from `Object` return?