skip to content

Object Methods & Contracts

The methods every Java object inherits and the contracts they carry: equals, hashCode, toString, clone and the deprecated finalize. Getting equals and hashCode right is one of the most reliably asked Java topics because breaking them silently breaks collections.

part ofJavaoverview, primer and where to startread it →
on this pageshow

explore

questions

page 1 of 2

What is the Comparable interface in Java and what does its compareTo method return?

level: juniorimportance: must knowfreq 70%

answer

  1. One method: int compareTo(T)
  2. Sign matters, not magnitude: neg/zero/pos
  3. this < other => negative
  4. Defines the natural ordering
  5. Integer.compare, never a - b

basics

~10 s

Comparable defines a type's natural ordering through one method, compareTo. It returns a negative number if this object is smaller, zero if equal in order, and a positive number if larger.

solid answer

~40 s

Comparable<T> is a generic interface with a single method, int compareTo(T other), that defines a type's natural ordering. The return value is a sign, not a magnitude: negative means this comes before other, zero means they are equal in ordering, positive means this comes after. Implementing it lets a type be sorted by Collections.sort/Arrays.sort and used as a key in sorted structures like TreeSet and TreeMap without an explicit Comparator. Many standard types implement it: Integer, String (lexicographic), LocalDate (chronological), enums (declaration order). When ordering by multiple fields, compare them in priority order and return the first non-zero result. Prefer Integer.compare/Long.compare or Comparator.comparing chains over hand-written subtraction, which can overflow.

go deeper

for a junior

Knows Comparable has one method compareTo returning negative/zero/positive for less/equal/greater, and that implementing it enables sorting.

for a middle

Can implement multi-field compareTo correctly, uses Integer.compare/Comparator chains, and distinguishes Comparable from Comparator.

for a senior

Articulates the sign-not-magnitude rule, overflow pitfalls of subtraction, and which JDK types provide natural orderings and why.

for a principal

Frames natural ordering as an API design choice — when a type deserves one canonical order vs. forcing callers to supply a Comparator, and the maintenance cost of a baked-in ordering.

## What problem this solves Sorting and ordered storage need a way to ask: given two objects of the same type, which one comes first? Java expresses this through the **`Comparable`** interface, which defines a type's **natural ordering** — the single, default way instances of that type line up. ## The interface `java.lang.Comparable<T>` has exactly one method: ```java public interface Comparable<T> { int compareTo(T o); } ``` The `<T>` is a **generic type parameter** — a placeholder for the type being compared, filled in when you implement the interface (e.g. `class Money implements Comparable<Money>`). This makes the parameter type-safe: you write `compareTo(Money other)`, not `compareTo(Object other)`. ## What the return value means `compareTo` returns an **`int`**, but only its **sign** matters — not the magnitude: - **negative** (conventionally -1): `this` object is **less than** (comes before) `o`. - **zero**: `this` and `o` are **equal in ordering** (neither comes first). - **positive** (conventionally +1): `this` object is **greater than** (comes after) `o`. A mnemonic: `a.compareTo(b)` answers "`a` minus `b`" in spirit — positive if `a` is bigger. ## Who uses it Once a type implements `Comparable`, it works automatically with: - `Collections.sort(list)` and `Arrays.sort(array)` — sort by natural order. - `TreeSet<T>` and `TreeMap<T,?>` — keep elements/keys sorted; ordering by natural order. - `Collections.max`/`min`, `PriorityQueue`, binary search. Many JDK types already implement it: `Integer`/`Long`/`Double` (numeric), `String` (lexicographic, char-by-char), `LocalDate`/`Instant` (chronological), and **enums** (in declaration order via `ordinal`). ## Single field example ```java record Version(int major) implements Comparable<Version> { public int compareTo(Version other) { return Integer.compare(this.major, other.major); } } ``` `Integer.compare(a, b)` returns the correct sign **without overflow**. Writing `a - b` looks tempting but breaks when the subtraction overflows the `int` range (e.g. `Integer.MIN_VALUE - 1` wraps to a positive number), silently reversing the order. ## Multiple fields Compare fields in priority order; return at the first non-zero result: ```java int c = Integer.compare(this.year, o.year); if (c != 0) return c; return this.title.compareTo(o.title); ``` or, more readably, `Comparator.comparingInt(Version::major).thenComparing(...)` (a `Comparator` is the *external* sibling of `Comparable` — same sign convention, supplied separately instead of baked into the type). ## Comparable vs Comparator (one line) `Comparable` lives **on the type** and defines its one natural order; `Comparator` is a **separate object** you pass in to sort the same type many different ways. You will reach for `Comparator` whenever you need an ordering other than natural order, or for a type you can't modify.

  • Why prefer Integer.compare(a, b) over returning a - b?
    Subtraction can overflow the int range and wrap around to the wrong sign, silently corrupting the ordering. Integer.compare branches safely and always returns the correct sign.
  • What is the difference between Comparable and Comparator?
    Comparable is implemented by the type itself and defines its single natural ordering. Comparator is a separate object passed in, letting you order a type many ways or order types you cannot modify.

saying these in an interview costs you the question

  • Saying compareTo returns true/false or a boolean
  • Claiming the magnitude of the int is meaningful (it is not)
  • Using a - b subtraction (overflow risk) instead of Integer.compare
  • Confusing Comparable (on the type, natural order) with Comparator (external)

context

open as a page

What does the default Object.equals() method compare, and how does that differ from the == operator?

level: juniorimportance: must knowfreq 78%

basics

~10 s

By default, equals() checks whether two references point to the exact same object in memory — the same as ==. To compare by value (content), you must override equals() yourself.

open as a page

Walk through how you implement equals() for a Java class. What checks do you perform, and in what order?

level: juniorimportance: must knowfreq 80%

basics

~20 s

First check if the other object is the same one (==). Then check it isn't null and is the right type. Then cast it and compare each field that defines equality, using Objects.equals for object fields so nulls are handled safely.

open as a page

Why must you override hashCode() whenever you override equals() in Java?

level: juniorimportance: must knowfreq 90%

basics

~20 s

Because Java's hash-based collections (like HashMap and HashSet) first use hashCode() to find the right bucket, then equals() to compare. If equal objects return different hash codes, they land in different buckets and the collection never finds the match.

open as a page

What is the hashCode() contract in Java? State its rules.

level: juniorimportance: must knowfreq 82%

basics

~20 s

hashCode() returns an int for an object. Two rules matter: if two objects are equal (equals() is true), they must return the same hashCode; and a hashCode must stay the same across repeated calls during one run. Unequal objects may share a code.

open as a page

Every Java class implicitly inherits from java.lang.Object. Which methods does that give every object, and what is each for?

level: juniorimportance: must knowfreq 72%

basics

~10 s

Every object inherits from Object: equals (logical equality), hashCode (an int for hash collections), toString (a text form), getClass (its runtime class), clone (copying), the deprecated finalize, plus wait/notify/notifyAll for thread coordination.

open as a page

What does the default Object.toString() return, and why is it usually not useful?

level: juniorimportance: must knowfreq 70%

basics

~20 s

By default toString() returns the class name, an '@', and the object's hash code in hexadecimal, like Point@1b6d3586. It identifies the type but shows none of the object's data, so it is rarely helpful for reading or logging.

open as a page

What is the difference between a shallow copy and a deep copy, and how do you implement a deep clone in Java?

level: middleimportance: must knowfreq 68%

basics

~20 s

A shallow copy duplicates the object but its reference fields still point to the same inner objects, so changes to those inner objects are seen by both. A deep copy also copies the inner objects, so the two are fully independent.

open as a page

State the five formal clauses of the equals() contract (as in Object's Javadoc) and what each requires.

level: middleimportance: must knowfreq 84%

basics

~10 s

equals() must be: reflexive (x equals itself), symmetric (if x equals y then y equals x), transitive (x=y and y=z implies x=z), consistent (same result on repeated calls), and x.equals(null) must return false.

open as a page

What is the relationship between the equals contract and hashCode, and what concretely goes wrong in a HashMap or HashSet if you override one but not the other?

level: middleimportance: must knowfreq 80%

basics

~20 s

If two objects are equal by equals(), they must return the same hashCode(). Override equals without hashCode and a HashMap/HashSet may store duplicates or fail to find a value, because it looks in the wrong bucket.

open as a page

Walk through exactly how HashMap uses hashCode() and equals() during a get(), and pinpoint where a broken hashCode causes the lookup to fail.

level: middleimportance: must knowfreq 75%

basics

~20 s

HashMap first calls hashCode() on the key to choose a bucket (an array slot), then walks the entries in that bucket calling equals() to find the exact key. If hashCode() is wrong, it picks the wrong bucket, so the right entry is never visited and equals() never runs.

open as a page

If you put an object into a HashSet (or as a HashMap key) and then mutate a field that its hashCode depends on, what happens when you later try to look it up or remove it, and why?

level: middleimportance: must knowfreq 70%

basics

~20 s

The object gets 'lost' in the set. Hash collections place keys into buckets by hashCode. Change a field used in hashCode and the new hashCode points to a different bucket, so lookups, contains, and remove no longer find it.

open as a page

Why can mutating a field used in hashCode() make an object disappear from a HashSet, given the consistency clause?

level: middleimportance: must knowfreq 60%

basics

~20 s

HashSet remembers the bucket it put the object in, chosen from the hashCode at insert time. If you change a field that hashCode uses, the new hashCode points to a different bucket — so contains() looks in the wrong place and the object seems gone.

open as a page

Why does Effective Java discourage clone()/Cloneable, and what should you use instead?

level: seniorimportance: must knowfreq 62%

basics

~20 s

clone() has many flaws: Cloneable is a marker interface that magically changes Object.clone(), the default copy is shallow, it throws a checked exception, and it skips constructors so it clashes with final fields. Effective Java recommends a copy constructor or copy factory instead.

open as a page

What does it mean for compareTo to be consistent with equals, and when is it acceptable to break that consistency?

level: seniorimportance: must knowfreq 65%

basics

~10 s

Consistent means x.compareTo(y) == 0 exactly when x.equals(y) is true. It is strongly recommended but not required. Breaking it is allowed if documented, but it can make sorted collections behave surprisingly.

open as a page

How does Object.clone() work in Java, and what is the role of the Cloneable interface?

level: juniorimportance: should knowfreq 55%

basics

~20 s

clone() makes a copy of an object. To use it, your class must implement Cloneable; otherwise calling clone() throws CloneNotSupportedException. The default copy is shallow — it copies field values but not the objects they point to.

open as a page

Why are immutable objects considered the ideal keys for hash-based maps and sets?

level: juniorimportance: should knowfreq 50%

basics

~20 s

Because an immutable object's state can never change after it's created, its hashCode can never change either. So once you put it in a HashMap or HashSet, it always stays in the right bucket and you can always find it again.

open as a page

What is the finalize() method in Java, and when is it called?

level: juniorimportance: should knowfreq 45%

basics

~10 s

finalize() is a method on java.lang.Object that the garbage collector may call once before it reclaims an object's memory, to let the object clean up. You can't control when (or even whether) it runs.

open as a page

What does Object.toString() return by default, and why is that often unhelpful for logging?

level: juniorimportance: should knowfreq 58%

basics

~20 s

By default toString() returns the class name, an '@', and the hashCode in hex, like Point@1b6d3586. It is auto-called in println and string concatenation, but shows no field values, so logs look cryptic unless you override it.

open as a page

How does a type's natural ordering relate to equality, and how do you choose between Comparable and Comparator?

level: middleimportance: should knowfreq 55%

basics

~20 s

Natural ordering is the single default order a type defines via Comparable. Ideally it matches equals. Use Comparable for the one canonical order; use a Comparator passed in when you need other orderings or can't change the type.

open as a page

What relational properties must a correct compareTo implementation satisfy, and what breaks if you violate them?

level: middleimportance: should knowfreq 50%

basics

~20 s

compareTo must impose a total order: it must be antisymmetric (if x is less than y then y is greater than x), transitive (if x < y and y < z then x < z), and reflexive (x compares 0 to itself). Violating these makes sorting and TreeMap behave unpredictably.

open as a page

Write a correct, contract-compliant equals() for a value class and explain each step, including the use of instanceof, null handling, and field comparison.

level: middleimportance: should knowfreq 70%

basics

~20 s

Start with an identity fast-path (this == o), then an instanceof check that also rejects null and wrong types, cast, and compare the significant fields with == for primitives and equals() for objects. Override hashCode over the same fields.

open as a page

How do you implement hashCode() by hand, and why is the multiplier 31 used in the classic formula?

level: middleimportance: should knowfreq 60%

basics

~20 s

Start with a number, then for each field do result = 31 * result + fieldHash. The 31 mixes the fields so different objects spread out across buckets. Today you usually just write Objects.hash(field1, field2, ...) instead of doing it by hand.

open as a page

Show a correct, contract-honoring equals()/hashCode() pair and explain how each line keeps the two consistent.

level: middleimportance: should knowfreq 70%

basics

~20 s

Compare the same fields in both methods. In equals(): check identity, check the type, then compare each field (null-safe with Objects.equals). In hashCode(): combine those same fields with Objects.hash(...). Same fields in => consistent results out.

open as a page

When implementing hashCode() and equals(), how do you decide which fields to include, and why are mutable fields a problem?

level: middleimportance: should knowfreq 55%

basics

~20 s

Base equals/hashCode on fields that don't change after the object is created — ideally a stable identifier. Mutable fields are a problem because if they change while the object is a key in a hash collection, its hashCode changes and the entry can no longer be found.

open as a page

Why was finalize() deprecated, and what are its replacements for resource cleanup?

level: middleimportance: should knowfreq 50%

basics

~20 s

finalize() is unreliable: you can't predict when it runs, it may never run, it slows down GC, and it has dangerous edge cases. Java deprecated it in 9. Use try-with-resources (AutoCloseable) for deterministic cleanup and Cleaner as a safety net.

open as a page

What does the default Object.hashCode() return, and what does 'not stable across JVM runs' mean for it?

level: middleimportance: should knowfreq 40%

basics

~20 s

If a class doesn't override hashCode(), it gets an identity hash: a number tied to that specific object instance, the same every time you ask during one run. It is not the memory address, and a fresh run of the program can produce different numbers.

open as a page

Why is Object.clone() protected and why does calling clone() on a class without Cloneable fail?

level: middleimportance: should knowfreq 55%

basics

~20 s

clone() is protected so it isn't a public API by default. Object.clone() checks for the Cloneable marker interface; without it, it throws CloneNotSupportedException. Cloneable carries no methods — it just flips clone() from throwing to copying.

open as a page

What does getClass() return, why is it final, and how does it differ from instanceof for type checks?

level: middleimportance: should knowfreq 50%

basics

~20 s

getClass() returns the exact runtime Class of an object. It's final so the JVM always reports the true type. getClass() matches only the exact class; instanceof matches the class and any subtype, so instanceof is more permissive.

open as a page

Where is toString() invoked automatically, and how is null handled in those paths?

level: middleimportance: should knowfreq 50%

basics

~10 s

toString() runs automatically during string concatenation with +, in System.out.println(obj), and via String.valueOf(obj). Those paths handle a null reference by printing "null" instead of throwing.

open as a page

showing 1–30 of 51