Java Interview Questions

Commonly asked Java interview questions with clear, practical answers.

A curated set of Java interview questions, ordered roughly from fundamentals to more advanced — the kind you'll actually be asked in real screens and on-sites.

Language fundamentals

Q: What's the difference between == and .equals()? == compares references for objects (whether two variables point to the same object in memory) or raw values for primitives. .equals() compares logical/content equality, and classes like String and the wrapper types override it to do so meaningfully.

Q: Why are Java Strings immutable? Immutability makes strings safe to share across threads without synchronization, enables the JVM's string pool (identical literals can safely share one object), and prevents security issues like a caller mutating a string after it was validated (e.g., a file path or SQL fragment).

Q: What's the difference between ArrayList and LinkedList? ArrayList is backed by a resizable array — O(1) random access, but O(n) insertion/removal in the middle. LinkedList is a doubly-linked list — O(1) insertion/removal at known positions, but O(n) random access. In practice, ArrayList is the right default almost all the time.

Q: What is autoboxing? Automatic conversion between a primitive (int) and its wrapper class (Integer) — e.g., passing an int where an Integer (or a generic type parameter) is expected. It's convenient but can hurt performance in tight loops and has a classic gotcha: Integer objects outside the range -128 to 127 are not cached, so == comparisons on boxed integers can silently give wrong results — use .equals().

OOP

Q: What is the difference between method overloading and overriding? Overloading is defining multiple methods with the same name but different parameters in the same class — resolved at compile time. Overriding is a subclass providing its own implementation of a method inherited from its parent — resolved at runtime (dynamic dispatch).

Q: Can you override a private or static method? No. private methods aren't visible to subclasses at all. static methods belong to the class, not an instance, so a subclass defining a method with the same signature hides the parent's version rather than overriding it — no polymorphism applies.

Q: What is the purpose of the final keyword? On a variable: it can only be assigned once. On a method: it cannot be overridden by subclasses. On a class: it cannot be extended at all (e.g., String is final).

Collections & streams

Q: Why does HashMap allow one null key but Hashtable doesn't? HashMap is a newer, non-synchronized API designed with more permissive null-handling; Hashtable is a legacy, synchronized class from Java 1.0 that never allowed null keys or values, largely for historical implementation reasons.

Q: How does HashMap actually find a value by key? It computes key.hashCode(), uses that to pick a bucket, then uses key.equals() to find the exact matching entry within that bucket (multiple keys can hash to the same bucket — a "collision" — resolved via a linked list or, since Java 8, a balanced tree for large buckets).

Concurrency

Q: What is the difference between synchronized and volatile? synchronized provides both mutual exclusion (only one thread in the block at a time) and visibility (changes are flushed to main memory). volatile only guarantees visibility — every read sees the latest write — without providing mutual exclusion, so it's suitable for simple flags, not compound operations like count++.

Q: What is a deadlock? A situation where two or more threads are each waiting for a lock the other holds, so none of them can proceed. A classic cause: acquiring multiple locks in inconsistent order across different threads.

Practical / design

Q: How would you design a thread-safe counter without using synchronized? Use java.util.concurrent.atomic.AtomicInteger, which relies on lock-free CPU-level compare-and-swap (CAS) instructions instead of locking — faster under contention for simple numeric operations.

Q: What's the advantage of programming to an interface rather than a concrete class? The calling code depends only on the contract (List, Payable, Repository), not a specific implementation — so the implementation can be swapped (e.g., ArrayListLinkedList, a real repository → an in-memory fake for tests) without touching any calling code.

Performance & the JVM

Q: Why might calling parallelStream() on a collection actually make a program slower? Parallel streams hand work to the shared ForkJoinPool, which has real coordination costs — splitting the source, dispatching to threads, and merging partial results. For a small collection or cheap per-element work, that overhead outweighs any gain from running on multiple cores, so the sequential version wins. Parallel streams only pay off with a source that splits efficiently (array/ArrayList-backed) and substantial CPU-bound work per element and enough elements to amortize the coordination cost.

Q: What's the difference between a minor GC and a full GC, and why does it matter for a latency-sensitive service? A minor GC collects only the young generation (Eden and the survivor spaces), which is small and almost always mostly garbage, so it's fast — typically single-digit to low double-digit milliseconds. A full GC collects the old generation too, which is larger and has a much lower proportion of reclaimable garbage, making it dramatically more expensive — often an order of magnitude slower. A service with strict latency requirements cares specifically about full GC frequency and duration, since that's where visible request-time pauses come from; this is exactly why low-pause collectors like ZGC exist, doing nearly all of their work concurrently with the running application instead of stopping it.

Q: How does ConcurrentHashMap provide thread safety without locking the entire map on every read or write? Unlike a synchronized wrapper around a HashMap (which serializes every access behind one lock), ConcurrentHashMap divides its internal storage so that operations only need to briefly synchronize on the specific bucket (or node) they're touching, letting unrelated updates to different buckets proceed fully in parallel. Reads are largely lock-free entirely, relying on volatile fields and safe publication to see recent writes without blocking. The trade-off is that aggregate operations like size() are only approximately accurate at any single instant in a highly concurrent map, since they can't atomically freeze the entire structure to count it.

Q: What's the difference between a soft reference, a weak reference, and a phantom reference? All three let an object be garbage collected even while something still points to it, but they differ in exactly when. A WeakReference is cleared as soon as the garbage collector determines the object has no other strong references — useful for things like canonicalizing caches (WeakHashMap) where an entry shouldn't outlive its key. A SoftReference is cleared only when the JVM is actually under memory pressure and needs the space, making it a reasonable fit for memory-sensitive caches that should hold data as long as there's room to spare. A PhantomReference is enqueued only after the object has already been finalized and its memory reclaimed, and its get() always returns null — it exists purely so cleanup code can run a side effect (like releasing a native resource) at the moment an object is actually gone, via a ReferenceQueue, rather than to access the object itself.