Object Class
Every class you write in Java silently extends one special class: java.lang.Object. It sits at the very top of the class hierarchy, which means every object you ever create — whether it’s a String, an ArrayList, or your own custom Person class — is also an Object. Understanding it unlocks a lot of Java’s most fundamental behaviors.
What is the Object Class?
java.lang.Object is the root superclass of all Java classes. If a class does not explicitly extend another class, the compiler automatically inserts extends Object for you. This means every class inherits a common set of methods that are always available.
// These two declarations are identical from the JVM's perspective
public class Dog { }
public class Dog extends Object { }
Because every class inherits from Object, you can always assign any object to a variable of type Object:
Object obj = new Dog(); // perfectly valid
Object str = "Hello"; // String is also an Object
Key Methods of the Object Class
The Object class defines eleven methods. The ones you will use most often are listed below.
| Method | Return Type | Purpose |
|---|---|---|
toString() | String | Returns a string representation of the object |
equals(Object o) | boolean | Checks logical equality with another object |
hashCode() | int | Returns a hash code integer for the object |
getClass() | Class<?> | Returns the runtime class of the object |
clone() | Object | Creates and returns a shallow copy |
finalize() | void | Called by GC before object is collected (deprecated) |
wait() / notify() / notifyAll() | void | Used for inter-thread communication |
toString()
By default, toString() returns a string like ClassName@hexHashCode, which is rarely useful. You should always override it to return something meaningful.
public class Point {
int x, y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public String toString() {
return "Point(" + x + ", " + y + ")";
}
}
public class Main {
public static void main(String[] args) {
Point p = new Point(3, 7);
System.out.println(p); // calls toString() automatically
System.out.println(p.toString());
}
}
Output:
Point(3, 7)
Point(3, 7)
Tip:
System.out.println()and string concatenation both calltoString()automatically. Overriding it makes debugging much easier.
equals()
The default equals() from Object checks reference equality — it returns true only if both variables point to the exact same object in memory. Override it when you want to compare objects by their content instead.
public class Book {
String title;
String author;
Book(String title, String author) {
this.title = title;
this.author = author;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Book)) return false;
Book other = (Book) o;
return title.equals(other.title) && author.equals(other.author);
}
}
public class Main {
public static void main(String[] args) {
Book b1 = new Book("Clean Code", "Martin");
Book b2 = new Book("Clean Code", "Martin");
Book b3 = b1;
System.out.println(b1 == b2); // false — different objects
System.out.println(b1.equals(b2)); // true — same content
System.out.println(b1 == b3); // true — same reference
}
}
Output:
false
true
true
Warning: If you override
equals(), you must also overridehashCode(). Failing to do so breaks contracts relied upon byHashMap,HashSet, and other collections.
hashCode()
hashCode() returns an integer used by hash-based collections to quickly locate an object. The contract is:
- Two objects that are
equals()must have the samehashCode. - Two objects with the same
hashCodedo not have to beequals(a hash collision is allowed).
import java.util.Objects;
public class Book {
String title;
String author;
Book(String title, String author) {
this.title = title;
this.author = author;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Book)) return false;
Book other = (Book) o;
return title.equals(other.title) && author.equals(other.author);
}
@Override
public int hashCode() {
return Objects.hash(title, author); // combines fields into a good hash
}
}
Tip:
java.util.Objects.hash(...)(available since Java 7) is the easiest and safest way to implementhashCode()for multiple fields.
getClass()
getClass() returns the runtime Class object, which lets you inspect the actual type of an object even when you’re holding a reference to a supertype or interface.
Object obj = "Hello, World!";
System.out.println(obj.getClass().getName());
System.out.println(obj.getClass().getSimpleName());
Output:
java.lang.String
String
This is the foundation of Java’s Reflection API, which lets you inspect and manipulate classes at runtime.
clone()
clone() creates a shallow copy of an object. To use it, your class must implement the Cloneable marker interface and override clone() with a public modifier.
public class Config implements Cloneable {
String host;
int port;
Config(String host, int port) {
this.host = host;
this.port = port;
}
@Override
public Config clone() throws CloneNotSupportedException {
return (Config) super.clone();
}
}
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
Config original = new Config("localhost", 8080);
Config copy = original.clone();
copy.port = 9090;
System.out.println("Original port: " + original.port);
System.out.println("Copy port: " + copy.port);
}
}
Output:
Original port: 8080
Copy port: 9090
See Object Cloning for a deep dive into shallow vs. deep copies and the pitfalls of the Cloneable approach.
wait(), notify(), and notifyAll()
These three methods support inter-thread communication. They can only be called from within a synchronized block. wait() causes the current thread to pause until another thread calls notify() or notifyAll() on the same object.
Under the Hood
How the JVM Represents Object
Every object in the Java heap is prefixed with an object header that the JVM maintains. In HotSpot JVM, this header contains:
- Mark word (8 bytes on 64-bit) — stores the hash code, lock state (biased/thin/fat lock), and GC age bits.
- Class pointer (4–8 bytes) — a reference to the
Classmetadata (thegetClass()result lives here).
When you call Object.hashCode() without overriding it, the JVM computes a value from the mark word (typically derived from the object’s identity — not necessarily its memory address on modern JVMs) and caches it there for subsequent calls.
equals() and hashCode() in Collections
When you put an object into a HashMap or HashSet, Java first calls hashCode() to determine which bucket (array slot) to use. Then it calls equals() to resolve collisions within that bucket. If you break the equals/hashCode contract, the same logical key can end up in two different buckets, and lookups will silently fail. See Working of HashMap for the full story.
The finalize() Method
finalize() was called by the garbage collector just before an object was reclaimed. It was deprecated in Java 9 and marked for removal because it offered no reliable guarantees and caused GC pauses. Use try-with-resources and java.lang.ref.Cleaner (Java 9+) instead. See Garbage Collection Deep-Dive for modern alternatives.
In This Section
This section covers miscellaneous but essential OOP utilities and language features that build on the foundation of the Object class:
- Object Cloning — Learn how to copy objects with
clone(), the difference between shallow and deep copies, and safer alternatives. - Math Class — Explore
java.lang.Mathfor common mathematical operations likepow(),sqrt(),abs(), and trigonometry. - Wrapper Classes — Understand how Java wraps primitives like
intandcharin objects (Integer,Character) and how autoboxing works. - Recursion — Master recursive methods — functions that call themselves — including base cases, call-stack mechanics, and common examples.
- Call by Value — See why Java always passes arguments by value and what that means for both primitives and object references.
- Enums — Use
enumto define a fixed set of named constants with type safety, fields, and methods. - Command-Line Arguments — Learn how to pass and read arguments through
String[] argsinmain()to make your programs configurable at runtime.
Related Topics
- Classes & Objects — Objects are instances of classes; understand the relationship before diving into
Object’s methods. - Inheritance — Because every class inherits from
Object, understanding inheritance helps you see why these methods are universally available. - toString() Method — A focused guide on overriding
toString()effectively for clean output and logging. - Working of HashMap — See exactly how
equals()andhashCode()power Java’s most popular data structure. - Wrapper Classes — Wrapper classes override
equals(),hashCode(), andtoString()fromObjectin well-defined, predictable ways. - Reflection API —
getClass()is your entry point to Java’s powerful runtime introspection capabilities.