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 pageshowhide
explore
- java.lang.Object Methods Overview6 questions
- equals Contract5 questions
- hashCode Contract5 questions
- equals/hashCode Interdependence5 questions
- Implementing equals & hashCode5 questions
- Mutability & Key Hazards5 questions
- compareTo & Ordering Contracts5 questions
- toString5 questions
- Cloning & clone()5 questions
- finalize (Deprecated)5 questions
questions
page 2 of 2How should you write a good toString() override, and what should it contain?
basics
~10 sOverride 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.
Why is it significant that clone() bypasses constructors, and how does that affect final fields and invariants?
basics
~20 sclone() 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.
Why might a TreeMap fail to find a key it actually contains, and how does this trace back to compareTo?
basics
~20 sTreeMap 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.
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?
basics
~20 sAdding 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.
How do you correctly compare and hash float, double, and array fields inside equals() and hashCode()?
basics
~10 sFor 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.
In an equals() implementation, what is the trade-off between using getClass() and instanceof for the type check?
basics
~20 sgetClass() 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.
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?
basics
~20 sThe 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.
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?
basics
~10 sDon'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.
Beyond correctness, what makes a hashCode() implementation 'good', and why does it matter for HashMap performance?
basics
~20 sA 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.
Why was finalize() deprecated, and what should you use instead for resource cleanup?
basics
~20 sfinalize() 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.
Why do wait(), notify() and notifyAll() live on java.lang.Object rather than on Thread, and what rule governs calling them?
basics
~20 sEvery 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.
Does toString() have a formal contract like equals() and hashCode(), and what are the consequences?
basics
~20 sNo. 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.
How should the return type and access modifier of an overridden clone() be declared, and why?
basics
~20 sObject.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.
How does Java's finalize() differ from a C++ destructor, and why doesn't Java have deterministic destructors?
basics
~20 sA 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.
Explain the object resurrection problem with finalize(), and why an object's finalize() never runs a second time.
basics
~20 sInside 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.
How do records, enums, arrays, and standard collections behave with toString(), and when must you still override it?
basics
~20 sRecords, 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.
Given Java records and IDE/Lombok generators, when should you still hand-write equals() and hashCode(), and what governs that decision?
basics
~20 sMost 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.
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?
basics
~20 sIf 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.
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?
basics
~20 sIf 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.
You own native (off-heap) memory in a Java class. Design a cleanup strategy without finalize(). What are the key pitfalls?
basics
~20 sMake 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.
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?
basics
~20 sIf 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.
showing 31–51 of 51