🪪
OOP

Object Class: equals, hashCode, toString

Every Object's Built-in Toolkit
💡 Every Java object has a "default ID card" (from the Object class) — toString() gives its name, equals() recognizes "is this the same thing", hashCode() gives a unique-ish number for fast lookup.

Every class implicitly extends the Object class, so every object gets toString(), equals(), and hashCode() for free.

The default toString() gives odd-looking text (like ClassName@hashcode) — which is why we override it for readable output.

equals() and hashCode() should be overridden together — this is essential for HashMap/HashSet to work correctly.

class Point {
  int x, y;
  public String toString() { return "(" + x + "," + y + ")"; }
  public boolean equals(Object o) {
    if (!(o instanceof Point)) return false;
    Point p = (Point) o;
    return x == p.x && y == p.y;
  }
}
🪪
Every Java object has a "default ID card" (from the Object class) — toString() gives its name, equals() recognizes "is this the same thing", hashCode() gives a unique-ish number for fast lookup.
1 / 5
⚡ Quick Recap
  • Every object gets these from the Object class
  • Override toString() for readable text
  • Override equals()+hashCode() together
On this page (4 subtopics)

equals() must follow a formal contract: reflexive (a.equals(a) is always true), symmetric (a.equals(b) == b.equals(a)), transitive (if a=b and b=c then a=c), and consistent (calling it repeatedly without changing data gives the same result). Breaking these rules causes weird, hard-to-debug bugs in Collections (HashMap, HashSet).

Rule: if two objects are equal by equals(), their hashCode() *must* also match (the reverse isn't required — different objects can share the same hashCode, called a "collision", and HashMap handles that fine). This is why, whenever you override equals(), always override hashCode() alongside it — otherwise duplicate detection in HashMap/HashSet breaks, and the same "equal" object could get added twice!

class Point {
  int x, y;
  public boolean equals(Object o) { /* x,y compare */ return true; }
  public int hashCode() { return Objects.hash(x, y); } // dono saath
}
⚠️Common Mistake: Overriding equals() but forgetting hashCode() is a very common bug — the code compiles fine (no error), but HashSet ends up allowing duplicates, against your intent.

The default toString() (ClassName@hashcode, like Point@1b6d3586) is useless for debugging. Override it to give a meaningful representation — like "Point{x=3, y=5}". IDEs and logging tools automatically use toString() whenever an object is printed or viewed in a debugger.

Calling .getClass() on any object gives you its runtime class (obj.getClass().getName()) — this is sometimes used in an equals() implementation instead of instanceof (for strict type matching). This is the entry point to the "Reflection" API — an advanced feature that lets you inspect/call classes/methods at runtime (frameworks like Spring depend heavily on this, for dependency injection).