JavaInterview Questions

Interview Questions

A collection of Java questions that come up repeatedly in technical interviews, with concise, correct answers. Use these to check your own understanding — being able to explain why, not just recite the answer, is what actually matters in an interview.

1. What is the difference between == and .equals()?

== compares references for objects (are these two variables pointing at the exact same object in memory?) and values for primitives. .equals() compares logical content, and its behavior depends on how the class overrides it — String, for instance, overrides equals() to compare character content, not identity. Two distinct String objects with the same characters are .equals()-equal but can be ==-unequal.

2. What is the difference between an abstract class and an interface?

An abstract class can hold state (instance fields), constructors, and a mix of implemented and abstract methods, but a class can extend only one abstract class. An interface traditionally held only method signatures (plus constants); since Java 8 it can also have default and static methods with bodies, but still no instance fields, and a class can implement any number of interfaces. Use an abstract class when subclasses share meaningful state or implementation; use an interface to describe a capability multiple unrelated classes can implement.

3. What is the difference between method overloading and overriding?

Overloading defines multiple methods with the same name but different parameter lists in the same class; the compiler resolves which one to call at compile time based on the argument types. Overriding provides a new implementation of an inherited method with the same signature in a subclass; which implementation runs is resolved at runtime based on the object’s actual type (dynamic dispatch).

4. Explain the equals()/hashCode() contract.

If two objects are equal according to .equals(), they must return the same value from .hashCode(). The reverse isn’t required — unequal objects may share a hash code (a “hash collision”), just less efficiently. Breaking this contract (overriding one without the other) causes hash-based collections like HashMap and HashSet to behave incorrectly: an object can be inserted and then appear “missing” when looked up, because it lands in a different bucket than the lookup expects.

5. What is autoboxing, and what pitfalls does it have?

Autoboxing is the compiler’s automatic conversion between a primitive (int) and its wrapper class (Integer) wherever one is needed but the other is supplied. Pitfalls: unboxing a null wrapper throws NullPointerException; comparing boxed values with == compares references, not content, and small cached values (Integer -128 to 127) can misleadingly appear ==-equal while larger ones don’t; and boxing inside tight loops adds object allocation overhead compared to primitives.

6. What is the difference between checked and unchecked exceptions?

Checked exceptions (subclasses of Exception, excluding RuntimeException) must be either caught or declared with throws — the compiler enforces handling them, typically for recoverable, expected failure conditions like IOException. Unchecked exceptions (subclasses of RuntimeException or Error) require no such declaration, typically representing programming errors (NullPointerException, IllegalArgumentException) that could happen almost anywhere and would be impractical to declare everywhere.

7. What is the Java Memory Model, at a high level?

The JVM splits memory mainly into the heap (where objects live, shared across all threads, managed by the garbage collector) and the stack (one per thread, holding local variables and method call frames). The Java Memory Model also defines rules for how changes made by one thread become visible to others — this is why constructs like volatile, synchronized, and the java.util.concurrent utilities exist: without them, one thread’s write to shared state isn’t guaranteed to be visible to another thread in a timely or ordered way.

8. What is the difference between ArrayList and LinkedList?

ArrayList is backed by a resizable array: fast O(1) random access by index, but inserting or removing from the middle requires shifting elements, an O(n) operation. LinkedList is backed by a doubly-linked list of nodes: O(1) insertion/removal at the ends (making it a good Deque), but O(n) random access since it must walk the chain of nodes. For most everyday use — iteration and index-based access — ArrayList is the better default.

9. What is a functional interface, and how do lambdas relate to it?

A functional interface is an interface with exactly one abstract method (it may have any number of default or static methods too) — Runnable, Comparator, and Function are all examples. A lambda expression is a compact, unnamed implementation of that single abstract method; wherever a functional interface type is expected, a lambda (or method reference) can be supplied in its place, without writing an explicit implementing class.

10. What does the Stream API let you do that loops don't?

Streams describe what transformation you want (filter, map, reduce) as a declarative pipeline rather than how to iterate, which often reads more clearly for data-transformation code, and supports parallel execution (.parallelStream()) without rewriting the pipeline. Streams don’t replace loops for everything — simple iteration with side effects, or code needing early-exit logic across multiple collections, is often clearer as a plain loop.

11. What is the difference between String, StringBuilder, and StringBuffer?

String is immutable — every apparent modification creates a new object. StringBuilder is a mutable, resizable character buffer for efficient repeated modification (e.g. inside a loop), but is not thread-safe. StringBuffer is the same idea as StringBuilder but with synchronized methods, making it thread-safe at the cost of extra overhead most single-threaded code doesn’t need — StringBuilder is the default choice today.

12. What happens if you don't override toString()?

The default Object.toString() returns the class name plus the object’s hash code in hexadecimal (e.g. com.example.Point@1b6d3586), which is rarely useful for debugging or logging. Overriding toString() to return meaningful field values makes objects far easier to inspect in logs, debuggers, and test failure messages.

13. What is the diamond problem, and how does Java avoid it?

The diamond problem arises when a class inherits from two sources that both define the same method, leaving ambiguity about which implementation applies. Java sidesteps it for state by disallowing multiple class inheritance (extends accepts only one class). For behavior, since interfaces can now have default methods, Java requires a class implementing two interfaces with conflicting default methods to explicitly override that method and resolve the conflict itself — the compiler refuses to guess.

14. What is the try-with-resources statement, and why use it?

try-with-resources automatically closes any resource implementing AutoCloseable when the try block finishes, whether normally or via an exception — replacing manual finally blocks that are easy to write incorrectly (forgetting a null check, or losing the original exception when close() itself throws). It’s the standard way to work with files, sockets, and JDBC connections/statements.

15. What is the difference between a shallow copy and a deep copy?

A shallow copy duplicates an object’s top-level fields, but any field that is itself a reference to another object still points at the same nested object as the original — mutating that nested object through the copy affects the original too. A deep copy recursively duplicates every referenced object as well, so the copy is fully independent. Java’s default clone() and copy constructors are typically shallow unless you write explicit logic to copy nested mutable fields.

16. What is the difference between a HashMap and a TreeMap?

HashMap offers average O(1) get/put by hashing keys, but makes no guarantee about iteration order. TreeMap keeps its keys sorted (by natural ordering or a supplied Comparator), backed by a red-black tree, giving O(log n) get/put but a predictable, sorted iteration order. Choose TreeMap when you need entries sorted by key; otherwise HashMap is faster for typical lookups.

17. Can you explain what a NullPointerException actually means?

It means code tried to use a reference — call a method on it, access a field, or index into it — while that reference held null, i.e. pointed at nothing. It’s not a special kind of error object failure; it’s simply the JVM refusing to dereference a non-existent object. Modern Java (14+) includes “helpful NullPointerExceptions” that name exactly which variable or method call in the expression was null, making these much faster to diagnose than in older versions.

18. What is the purpose of the final keyword?

final means “cannot change further,” applied to three different things: a final variable cannot be reassigned after initialization; a final method cannot be overridden by a subclass; a final class cannot be extended at all. It’s a tool for signaling and enforcing intended immutability or a closed design, not a performance optimization in itself.