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 2 of 2

How should you write a good toString() override, and what should it contain?

level: middleimportance: should knowfreq 55%

basics

~10 s

Override toString() to return a short, readable string with the object's important fields, for example "Point[x=3, y=4]". Keep it concise, include enough to identify the object, and avoid dumping huge or secret data.

open as a page

Why is it significant that clone() bypasses constructors, and how does that affect final fields and invariants?

level: seniorimportance: should knowfreq 48%

basics

~20 s

clone() builds a new object by copying fields directly in the JVM, without running any constructor. So validation and setup in your constructor never run, and you cannot reassign final fields to fresh deep copies — both make clone() risky and hard to get right.

open as a page

Why might a TreeMap fail to find a key it actually contains, and how does this trace back to compareTo?

level: seniorimportance: should knowfreq 40%

basics

~20 s

TreeMap locates keys using compareTo, not equals or hashCode. If compareTo is inconsistent, unstable, or based on mutable fields that changed, the tree search takes a wrong path and get returns null even though the key is stored.

open as a page

Why can you generally not extend an instantiable class, add a value-significant field, and still satisfy the equals contract? What is the recommended alternative?

level: seniorimportance: should knowfreq 58%

basics

~20 s

Adding a value field in a subclass forces a choice that breaks either symmetry or transitivity: the parent ignores the new field but the child checks it. Instead of inheriting, hold the parent as a field (composition) and expose a view.

open as a page

How do you correctly compare and hash float, double, and array fields inside equals() and hashCode()?

level: seniorimportance: should knowfreq 45%

basics

~10 s

For float/double use Float.compare/Double.compare (or Float.hashCode/Double.hashCode), not ==, because of NaN and -0.0. For arrays use Arrays.equals and Arrays.hashCode, not == or the array's own methods, which only check identity.

open as a page

In an equals() implementation, what is the trade-off between using getClass() and instanceof for the type check?

level: seniorimportance: should knowfreq 55%

basics

~20 s

getClass() requires the exact same class, so a subclass is never equal to its parent. instanceof allows subclasses to be equal. instanceof is more flexible but can make equality non-symmetric; getClass() is stricter but a subclass can never equal a parent.

open as a page

What happens if you mutate a field used in hashCode() after an object is already a key in a HashMap, and how do you avoid it?

level: seniorimportance: should knowfreq 55%

basics

~20 s

The object was filed in a bucket based on its old hash. After mutation its hash changes, so a fresh lookup computes the new hash and searches a different bucket. The entry is still in the old bucket, so the map can't find it — the key becomes a 'lost' entry that you can't get or remove normally.

open as a page

Your domain requires keys whose identifying fields legitimately change over time, yet you need them in a HashMap. How do you design around the mutable-key hazard?

level: seniorimportance: should knowfreq 35%

basics

~10 s

Don't let the changing fields drive hashCode. Either key the map on a separate stable id (storing the object as the value), use the remove-mutate-reinsert pattern, or make a snapshot/immutable copy as the key.

open as a page

Beyond correctness, what makes a hashCode() implementation 'good', and why does it matter for HashMap performance?

level: seniorimportance: should knowfreq 55%

basics

~20 s

A correct hashCode just needs equal objects to share a code. A good one also spreads unequal objects across many different codes, so HashMap buckets stay small and lookups stay fast. A poor spread piles items into few buckets and slows lookups.

open as a page

Why was finalize() deprecated, and what should you use instead for resource cleanup?

level: seniorimportance: should knowfreq 48%

basics

~20 s

finalize() ran before garbage collection with no timing guarantee, was slow, and could even resurrect objects, so it was unreliable for cleanup. It's deprecated since Java 9. Use try-with-resources (AutoCloseable) for deterministic cleanup, and Cleaner as a safety net.

open as a page

Why do wait(), notify() and notifyAll() live on java.lang.Object rather than on Thread, and what rule governs calling them?

level: seniorimportance: should knowfreq 45%

basics

~20 s

Every Java object has an intrinsic lock (monitor) and an associated wait-set, so the wait/notify methods belong on Object — the thing being locked. You must call them while holding that object's monitor (inside synchronized), or you get IllegalMonitorStateException.

open as a page

Does toString() have a formal contract like equals() and hashCode(), and what are the consequences?

level: seniorimportance: should knowfreq 35%

basics

~20 s

No. Unlike equals() and hashCode(), toString() has no binding contract — the docs only recommend a concise, informative, readable string. So nothing in the language forces a particular format, and you shouldn't rely on another class's toString() output programmatically.

open as a page

How should the return type and access modifier of an overridden clone() be declared, and why?

level: middleimportance: nice to knowfreq 35%

basics

~20 s

Object.clone() is protected and returns Object. When you override it, make it public so callers can use it, and use a covariant return type (return your own class) so callers don't have to cast the result.

open as a page

How does Java's finalize() differ from a C++ destructor, and why doesn't Java have deterministic destructors?

level: middleimportance: nice to knowfreq 30%

basics

~20 s

A C++ destructor runs at a predictable moment (when the object goes out of scope or is deleted). Java's finalize() runs whenever the garbage collector decides to, maybe never. Because Java auto-manages memory with a GC, it has no deterministic destructor; you use try-with-resources for predictable cleanup.

open as a page

Explain the object resurrection problem with finalize(), and why an object's finalize() never runs a second time.

level: seniorimportance: nice to knowfreq 25%

basics

~20 s

Inside finalize(), the object can store 'this' somewhere reachable, making itself live again (resurrected). Because finalize() runs at most once per object, the JVM won't call it again later, so any future cleanup is silently skipped.

open as a page

How do records, enums, arrays, and standard collections behave with toString(), and when must you still override it?

level: seniorimportance: nice to knowfreq 30%

basics

~20 s

Records, enums, and most collections give you a useful toString() automatically (e.g. Point[x=3, y=4], the enum constant name, [a, b, c]). Plain arrays don't — they print the default class@hash, so use Arrays.toString() or Arrays.deepToString() for them.

open as a page

Given Java records and IDE/Lombok generators, when should you still hand-write equals() and hashCode(), and what governs that decision?

level: principalimportance: nice to knowfreq 35%

basics

~20 s

Most of the time you should not hand-write them: use a record or a generator, which produce correct equals/hashCode from your fields. Hand-write only when you need custom equality, such as comparing a subset of fields, normalizing values, or handling array fields that records compare by identity.

open as a page

How can a naive equals()/hashCode() pair in a subclass that adds a field violate the contract or the equals symmetry/transitivity rules, and what are the principled options?

level: principalimportance: nice to knowfreq 35%

basics

~20 s

If a subclass adds a field and includes it in equals()/hashCode() while a superclass instance ignores it, comparisons can become asymmetric (a.equals(b) but not b.equals(a)) or break transitivity. The safe options are: don't add equality-relevant state to subclasses, use composition instead of inheritance, or use exact-class (getClass) equality.

open as a page

How can a mutated hash key cause a memory leak, and how would you detect and prevent this class of bug in a long-running service?

level: principalimportance: nice to knowfreq 22%

basics

~20 s

If a stored key's hashCode changes, you can no longer remove it by key, so the entry stays in the map forever — a slow leak as the map grows. Prevent it with immutable/id-based keys; detect it via heap growth and heap dumps showing maps full of unreachable-by-key entries.

open as a page

You own native (off-heap) memory in a Java class. Design a cleanup strategy without finalize(). What are the key pitfalls?

level: principalimportance: nice to knowfreq 22%

basics

~20 s

Make the class AutoCloseable and free the native memory in close(); callers use try-with-resources. Add a Cleaner as a safety net for forgotten closes, but make the cleanup action a separate object that holds only the native pointer, never a reference back to your class.

open as a page

When equals/hashCode are inherited across a class hierarchy, how can a subclass adding a field break the hashCode contract, and how do you avoid it?

level: principalimportance: nice to knowfreq 28%

basics

~20 s

If a subclass adds a field and changes equals/hashCode to use it, a parent object and a child object can end up 'equal' one way but with different hashCodes, breaking the rule that equal objects share a code. Avoid it by using composition instead of extending value classes, or by comparing exact classes.

open as a page

showing 31–51 of 51