Course topics

By WebNest Studio Engineering Team

Java - Core Tutorial

Object Class and Its Methods

Every class in Java, whether you write extends explicitly or not, ultimately extends java.lang.Object. This makes Object the root of the entire class hierarchy, and it guarantees that every Java object automatically inherits a small set of universally useful methods.

Why it matters

Every class inherits equals(), hashCode() and toString() from Object, and the default versions are rarely what you want: two objects with the same data are "not equal", and printing one shows a class name and a number. Overriding these correctly is what makes your objects work in a HashSet, as HashMap keys, and in log output.

Watch: Java Object Class Explained 🧬 toString, equals, hashCode, clone & More | Java Core Tutorial

A detailed guide to java.lang.Object and its methods, including toString(), equals(), hashCode(), clone(), getClass(), and the wait/notify methods.

Watch on YouTube

Core Methods Inherited from Object

A handful of Object methods are overridden constantly in everyday Java code, because their default behavior is rarely what a class actually needs.

  • toString() — returns a String representation of the object; the default prints the class name plus a hash code in hex, which is rarely useful and almost always worth overriding.
  • equals(Object obj) — compares two objects for logical equality; the default implementation only checks reference identity (the same object in memory).
  • hashCode() — returns an integer used by hash-based collections like HashMap and HashSet to bucket objects efficiently.
  • getClass() — returns the runtime Class object representing the object's actual class, useful for reflection and type checks.

The equals() and hashCode() Contract

Java requires a strict rule: if two objects are equal according to equals(), they must return the same value from hashCode(). The reverse is not required — equal hash codes do not imply the objects are equal (that is simply a hash collision). Breaking this contract by overriding one method but not the other causes subtle bugs where an object that "equals" another cannot be found in a HashMap or HashSet, because it lands in the wrong bucket.

Overriding These Methods Correctly

When you override equals(), you should also override hashCode() using the same fields that participate in the equality check, so the contract holds. Most IDEs and the java.util.Objects helper class (Objects.equals(), Objects.hash()) make this straightforward and less error-prone than writing it by hand.

Example

Overriding toString, equals, and hashCode consistently on a Point class

Java
import java.util.Objects;

class Point {
    int x, y;

    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public String toString() {
        return "Point(" + x + ", " + y + ")";
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (!(obj instanceof Point)) return false;
        Point other = (Point) obj;
        return x == other.x && y == other.y;
    }

    @Override
    public int hashCode() {
        return Objects.hash(x, y);
    }
}

public class ObjectMethodsDemo {
    public static void main(String[] args) {
        Point p1 = new Point(1, 2);
        Point p2 = new Point(1, 2);
        System.out.println(p1);
        System.out.println(p1.equals(p2));
        System.out.println(p1.hashCode() == p2.hashCode());
        System.out.println(p1.getClass().getName());
    }
}
Output
Point(1, 2)
true
true
Point

Common Mistakes

  • Overriding equals() without also overriding hashCode(), which silently breaks HashMap and HashSet lookups.
  • Using "==" to compare object content instead of equals() — "==" checks reference identity, not logical equality.
  • Forgetting to check "obj instanceof Point" (or a null check) inside equals(), risking a ClassCastException or NullPointerException.
  • Relying on the default toString() output in logs or debugging instead of overriding it with meaningful field values.

Exercise

Two Email objects should be equal when their addresses match, ignoring upper and lower case. At the moment the program prints false. Override equals() and hashCode() so it prints true.

Java · starter code
import java.util.HashSet;
import java.util.Set;

class Email {
    private final String address;

    Email(String address) {
        this.address = address;
    }

    // TODO: override equals() to compare addresses ignoring case
    // TODO: override hashCode() so equal emails have the same hash code
}

public class EmailDemo {
    public static void main(String[] args) {
        Set<Email> seen = new HashSet<>();
        seen.add(new Email("Asha@Example.com"));
        System.out.println(seen.contains(new Email("asha@example.com")));
    }
}
Show hints
  • In equals, check that the other object is an Email, then compare with equalsIgnoreCase.
  • The hash code must ignore case too: use address.toLowerCase().hashCode().
Show solution
Java · solution
import java.util.HashSet;
import java.util.Set;

class Email {
    private final String address;

    Email(String address) {
        this.address = address;
    }

    @Override
    public boolean equals(Object other) {
        if (this == other) {
            return true;
        }
        if (!(other instanceof Email)) {
            return false;
        }
        return address.equalsIgnoreCase(((Email) other).address);
    }

    @Override
    public int hashCode() {
        return address.toLowerCase().hashCode();
    }
}

public class EmailDemo {
    public static void main(String[] args) {
        Set<Email> seen = new HashSet<>();
        seen.add(new Email("Asha@Example.com"));
        System.out.println(seen.contains(new Email("asha@example.com"))); // true
    }
}

Quick quiz

1. What does the default equals() inherited from Object compare?

  • A. The values of all fields
  • B. Whether both references point to the same object
  • C. The class names
  • D. The hash codes only
Show answer

B. Object.equals() behaves like ==. Two separate objects are not equal until the class overrides equals().

2. What does the default toString() return?

  • A. The field values
  • B. An empty string
  • C. The class name, an @ sign and the hash code in hexadecimal
  • D. null
Show answer

C. For example Point@1b6d3586. Override toString() to return something meaningful.

3. If two objects are equal according to equals(), what must be true of their hash codes?

  • A. They must be different
  • B. There is no requirement
  • C. They must both be zero
  • D. They must be equal
Show answer

D. Equal objects must return the same hash code. Unequal objects may share one, although that makes hash tables slower.

Interview questions

What is the contract between equals() and hashCode()?

Show answer

If two objects are equal according to equals(), they must return the same hashCode(). The reverse is not required: two unequal objects may have the same hash code. The hash code must also stay the same for as long as the fields used in equals() do not change.

What goes wrong if you override equals() but not hashCode()?

Show answer

Hash-based collections stop working for that class. A HashSet or HashMap uses the hash code to choose a bucket before it ever calls equals(). Two equal objects with different default hash codes end up in different buckets, so contains() returns false and a set can hold duplicates.

Key Points to Remember

  • Every class implicitly extends Object and inherits toString(), equals(), hashCode(), and getClass().
  • The default equals() checks reference identity only; override it for logical equality.
  • Equal objects (by equals()) must produce equal hashCode() values.
  • Objects.equals() and Objects.hash() simplify writing correct, contract-respecting overrides.

Go deeper

Practice in the playground

Write and run your own code for this topic, or start from the exercise or an example. Runs plain Java 17. Frameworks such as Spring, and databases, are not available here. Your code for each topic is kept in this browser.

Run the examples

Change an input, predict the result, then compare it with the output. Explain why the result changes.

WebNest Studio

Written by

WebNest Studio Engineering Team

Practical lessons from developers working with Java, Python, React, databases and production systems.

Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering