Skip to content

Object Lifecycle — Interview Q&A

A curated set of 50 questions ranging from junior to staff-level. Use them as a self-quiz or as sources for designing real interview rounds.


Section A — Fundamentals (1-10)

Q1. What are the phases of an object's lifecycle in Java? A: Allocation → default initialization → constructor execution → reachable use → unreachability → (deprecated finalization) → reclamation. The first three are program-driven; the rest are GC-driven.

Q2. What does the new operator do? A: Resolves and (lazily) initializes the class, allocates heap memory big enough for the object's header + fields, zero-initializes all fields to their default values, runs the constructor chain (<init>), and returns a reference.

Q3. What are the default values for fields? A: Numeric primitives → 0, boolean → false, char → '', references → null. These apply to fields, not to local variables (locals must be assigned before reading).

Q4. Why are local variables not default-initialized? A: JLS treats local variables differently — the compiler enforces "definite assignment" rules so that you can't read an unassigned local. This catches bugs at compile time.

Q5. When is an object eligible for garbage collection? A: When no chain of references from any GC root can reach it. GC roots include static fields, locals on live thread stacks, JNI references, and active monitors.

Q6. Does Java guarantee when GC will run? A: No. GC timing is unspecified. System.gc() is a hint that the JVM may ignore. Don't rely on timing for correctness.

Q7. What's the difference between null-ing a reference and the object being collected? A: Setting a reference to null (or letting it go out of scope) makes the object eligible for collection. Actual reclamation happens later, on the GC's schedule.

Q8. What is <init>? A: The bytecode method synthesized for a constructor. It includes the super(...) or this(...) call, instance field initializers, instance initializer blocks, and the constructor body.

Q9. What is <clinit>? A: The bytecode method synthesized for class initialization. It contains all static field initializers and static { } blocks. Runs once per class, lazily on first use.

Q10. Can a constructor return a value? A: No. Constructors don't have a return type, not even void. The implicit return is the reference produced by new.


Section B — Initialization order (11-20)

Q11. What is the order of initialization in new Subclass()? A: Static init for all classes top-down (once ever) → allocate → zero-init → for each class top-down: super call → field inits → instance blocks → constructor body.

Q12. If parent class has a constructor that calls an overridable method, what does the child see? A: The override runs, but on a partially constructed child where field initializers haven't yet run — so it sees default values for child-declared fields. This is a famous trap: never call overridable methods from a constructor.

Q13. What's the difference between an instance initializer block and a static initializer block? A: Instance { } runs every new, before the constructor body, after super(...). Static static { } runs once when the class initializes.

Q14. Are field initializers and { } blocks merged into the constructor? A: Yes — javac inlines them into every constructor that ends with a super(...) call. Constructors that delegate via this(...) skip the prologue.

Q15. What if a class has multiple static { } blocks? A: They're concatenated in source order to form the body of <clinit>.

Q16. When is the <clinit> method skipped? A: When a class has no non-constant static field initializers and no static blocks. Reading a static final constant variable also doesn't trigger <clinit>.

Q17. Why doesn't Loader.SOME_FINAL_INT_CONSTANT trigger <clinit>? A: Constant variables (final primitive or String, initialized to a constant expression) are inlined at compile time — the loading class never references the source class at runtime.

Q18. Does subclass initialization initialize the parent? A: Yes for classes. For interfaces, only if the interface declares default methods.

Q19. What if <clinit> throws? A: The class is marked "erroneous." Subsequent attempts to use it throw NoClassDefFoundError (not the original ExceptionInInitializerError, which is the first encounter).

Q20. Is class initialization thread-safe? A: Yes — JLS §12.4.2 specifies a 12-step algorithm using a per-class initialization lock. At most one thread runs <clinit>; others wait.


Section C — Constructors (21-30)

Q21. Can a constructor call another constructor? A: Yes, via this(...) as the first statement. This is constructor chaining.

Q22. Can this(...) and super(...) both appear in the same constructor? A: No — only one, and it must be the first statement.

Q23. What if I write neither this(...) nor super(...)? A: The compiler inserts super() (no args). If the parent has no accessible no-arg constructor, this is a compile error.

Q24. Can a constructor be final, static, or abstract? A: No to all. These don't make sense — constructors aren't inherited, dispatched, or invokable independently of new.

Q25. Can constructors be overloaded? A: Yes. Each constructor has its own signature. Java picks one based on argument types at the call site.

Q26. Can a constructor throw checked exceptions? A: Yes, if declared in the throws clause. Callers must handle them.

Q27. What's a "leaking this" bug? A: When the constructor exposes the partially-constructed this to other code or threads — typically by registering it as a listener or starting a thread that uses this. Other code can observe defaults or inconsistent state.

Q28. What's the difference between String s = new String("x") and String s = "x"? A: The literal "x" is interned in the string pool — reused if the same content appears. new String("x") always allocates a fresh object on the heap.

Q29. Is constructor argument evaluation guaranteed left-to-right? A: Yes (JLS §15.7.4). Arguments are evaluated in left-to-right order before the constructor runs.

Q30. Does the JVM ever call a constructor without new? A: For typical Java code, no. Reflection (Constructor.newInstance) and serialization (ObjectInputStream) can bypass constructors — serialization in particular skips constructors of the deserialized class.


Section D — Garbage collection (31-40)

Q31. What is a GC root? A: A reference held outside the heap that GC starts tracing from. Includes static fields, local variables on live stacks, JNI references, and active synchronizers.

Q32. What are the generations in HotSpot's heap? A: Young (eden + 2 survivor regions) and old. G1 also has Humongous regions for large objects. ZGC since Java 21 is generational too.

Q33. What is a TLAB? A: Thread-Local Allocation Buffer. A chunk of eden assigned to one thread for fast bump-pointer allocation, no atomics, no locking.

Q34. What is the weak generational hypothesis? A: The empirical observation that most objects die young. GCs exploit this by collecting the young gen frequently and cheaply, and the old gen rarely.

Q35. What is escape analysis? A: A JIT optimization that determines whether an object's reference escapes the method. Non-escaping objects can be allocated on the stack (scalar replacement) — sometimes eliminating allocation entirely.

Q36. What is finalize() and why is it deprecated? A: Object.finalize() was meant to give objects a chance to release resources before reclamation. It's deprecated because timing is undefined, can resurrect objects, has security holes, and doubles GC pause cost. Removed for new types in Java 18+.

Q37. What is Cleaner and how does it differ from finalizers? A: java.lang.ref.Cleaner (Java 9+) lets you register a cleanup runnable for an object. The action runs on a daemon thread when the object is phantom-reachable. Unlike finalize, the cleanup runnable cannot resurrect the object and lives in a separate class with no implicit this pin.

Q38. What are weak, soft, and phantom references? A: Weak: cleared as soon as no strong refs remain. Soft: cleared under memory pressure (cache-friendly). Phantom: never returns the referent; signals "object is unreachable, run cleanup."

Q39. What's the difference between WeakHashMap and a regular HashMap? A: WeakHashMap holds keys via WeakReference. When a key has no strong references elsewhere, the entry can be removed during GC. Useful for caches keyed by short-lived objects.

Q40. How can you prevent class unloading? A: Hold a strong reference to a class loaded by the loader, or hold a Class<?> reference somewhere reachable from a long-lived loader. ClassLoader leaks happen this way and prevent webapp redeploys from freeing memory.


Section E — Memory model and concurrency (41-50)

Q41. What does JLS §17.5 say about final fields? A: A thread that observes a reference to a fully-constructed object is guaranteed to see the correct values of its final fields, without synchronization, provided this did not escape during construction.

Q42. Why can broken double-checked locking expose half-constructed objects? A: Without volatile, a writer thread can publish the reference before the constructor's writes are visible. Reader threads can observe instance != null but read defaults from its non-final fields.

Q43. How do you fix DCL? A: Make the field volatile (Java 5+ memory model), or use the lazy holder idiom (static class Holder { static final X INSTANCE = new X(); }), which leverages classloader-level synchronization.

Q44. What is "safe publication"? A: Releasing an object reference such that other threads see the fully-constructed state. Mechanisms: writing to a volatile field, locking, putting into a thread-safe collection, or storing in a final field of a properly published object.

Q45. Is static int x = 5; thread-safe? A: Yes. Class initialization runs under the JVM's class init lock, providing a happens-before edge between the initialization and any subsequent observation of the class.

Q46. What is "uninitializedThis" in bytecode? A: A verifier type representing the receiver of a constructor before its super(...) call has returned. The verifier rejects most operations on it to prevent observing partially constructed objects.

Q47. What happens if a constructor throws midway? A: The object is fully allocated and partially constructed, but the reference is never returned to the caller. The half-built object becomes unreachable and is eligible for GC. Any resources opened in the constructor before the throw are leaked unless cleaned up explicitly.

Q48. How do you avoid resource leaks in constructors that allocate resources? A: Allocate via a static factory method that uses try/catch to close resources before re-throwing, or restructure so the only constructor accepts already-opened resources.

Q49. What is scalar replacement? A: A C2 JIT optimization that, for non-escaping objects, replaces the object with its individual fields stored in registers/stack slots. The new becomes free; the heap doesn't grow.

Q50. What changes does Project Valhalla bring to object lifecycle? A: Value classes have no identity, no header, can be flattened in arrays, and are stack-allocatable by default. Their "lifecycle" reduces to compute → use → discard with no GC involvement.


Bonus — design / open-ended (51-60)

Q51. Walk me through what happens when you write String s = new String("hello"); A: Class String is already loaded. new allocates a String header + fields on the heap. Fields default-init to null/0. The String constructor runs, copying the char array from "hello" (which is interned). Reference is returned and assigned to s on the stack.

Q52. How would you safely register a listener from a constructor? A: Don't. Move registration to a static factory: var x = new X(); registry.add(x); return x;. This way, registration sees a fully-constructed object.

Q53. Why is Integer.valueOf(5) faster than new Integer(5)? A: valueOf returns cached instances for small values (-128..127 by default), avoiding allocation. new Integer(5) (deprecated for removal) always allocates.

Q54. When is System.gc() legitimate? A: Almost never in production. Acceptable in benchmarks (between iterations to clear noise) or in shutdown handlers. Note: -XX:+DisableExplicitGC makes it a no-op; many production deployments enable that.

Q55. How would you detect a memory leak in a JVM service? A: Capture a heap dump (jcmd <pid> GC.heap_dump path). Open in Eclipse MAT. Look at the dominator tree for objects rooting unexpectedly large amounts of memory. Investigate which references keep them alive.

Q56. Why are static final collections (like static final List<X> CACHE = new ArrayList<>()) leak-prone? A: They live as long as the class is loaded. Anything you put in them stays referenced and prevents collection. Use bounded caches (Caffeine, Guava) or weak references where appropriate.

Q57. What's wrong with this snippet: class A { static A instance = new A(); int x = 1; }? A: The static initializer runs new A() during A's <clinit>. The new A's instance field x = 1 runs after the static-instance reference is already published — but other threads observing instance during <clinit> could see partial state. Worse, instance.x is initialized after instance is set, but on the same thread it's fine — the cross-thread case is the bug.

Q58. A coworker claims setting fields to null in dispose() "helps the GC." Are they right? A: Almost never. The GC is pointer-tracing — it doesn't care whether a dead object's fields were nulled. In rare cases (long-lived objects holding references to large short-lived ones), nulling can help. As a default rule, it's superstition.

Q59. Can two threads call the same constructor concurrently? A: Yes — constructors aren't synchronized. Each new produces its own object; concurrent invocations don't share state. (Unless the constructor touches static state, which is its own problem.)

Q60. What's the difference between class loading, linking, and initialization? A: Loading: locate and parse the class file into runtime data. Linking: verify bytecode, prepare static fields (default values), resolve constant pool entries (lazy). Initialization: run <clinit>. Three distinct phases per JVMS §5; only the third is observable to user code.


How to use this list

  • For self-study: answer aloud, then read the answer. Mark the ones you missed.
  • For interview prep: if you can answer 40+ confidently, you're ready for senior Java roles.
  • For interviewers: mix one Q from each section. The pattern of which answers stumble is more diagnostic than the count.