Java Interview Questions & Answers (2026 Guide)
Java interviews test three axes: language depth (collections, generics, streams), concurrency (threads, locks, memory model), and JVM internals (GC, classloaders, JIT). This guide covers 18 questions we've seen candidates hit at TCS, Infosys, Wipro, Amazon, and Google interviews in the last 12 months. Grouped by difficulty. Enterprise Java bias — Spring and Hibernate questions included.
Beginner questions
1. What's the difference between == and .equals()? Beginner
== compares references (same object in memory). .equals() compares values (or whatever the class overrides it to mean). String.equals() compares character content. For custom classes, you must override BOTH equals() and hashCode() together — HashMap and HashSet depend on that contract. Autoboxing gotcha: Integer.valueOf(127) == Integer.valueOf(127) is true (cached), Integer.valueOf(128) == Integer.valueOf(128) is false (new objects).
2. What's the difference between ArrayList and LinkedList? Beginner
ArrayList is array-backed: O(1) get/set by index, O(n) insert/delete in the middle, resizing doubles the array. LinkedList is doubly-linked list: O(1) insert/delete at head/tail, O(n) get by index. Practical rule: use ArrayList by default. LinkedList is almost never faster except at both ends — and ArrayDeque beats it there too.
3. What's the difference between @Component, @Service, @Repository, @Controller? Beginner
All four are Spring stereotypes that register the class as a bean. @Repository adds automatic exception translation (Hibernate/JDBC exceptions → Spring DataAccessException). @Controller is for Spring MVC — routes HTTP. @Service is semantic — no extra behavior over @Component, just readability. @Component is the generic version.
4. What is the difference between checked and unchecked exceptions? Beginner
Checked exceptions (IOException, SQLException) MUST be caught or declared with throws — compiler enforces it. Unchecked exceptions (RuntimeException, Error) are optional. Design guidance: use unchecked for programmer errors (NullPointerException, IllegalArgumentException), checked for recoverable conditions the caller must handle. Modern Java tends toward unchecked — checked exceptions don't compose with streams.
Practice these live, in your voice
MiPrep's practice mode turns your resume into a rehearsed answer set. Talk through the idioms the way top-tier interviewers score.
Download MiPrep 🔒 Interview audio is never stored on our serversIntermediate questions
5. Explain HashMap internals. Intermediate
HashMap is an array of buckets. put(key, value): compute hash(key), map to bucket index via (n-1) & hash, walk linked list in bucket for equality, insert or overwrite. Since Java 8, when a bucket exceeds 8 entries and the table is > 64, the bucket converts to a red-black tree for O(log n) lookup. Resize happens at load factor 0.75 — array doubles, all entries rehashed. Interviewer follow-up: 'What if I use a mutable object as a key?' — the object's hash changes, you can never find the entry again.
6. Explain garbage collection in the JVM. Intermediate
Modern JVMs use generational GC: young generation (eden + 2 survivor spaces) for short-lived objects, old generation for long-lived. Young GC = minor GC = stop-the-world but fast (ms). Old GC = major GC = expensive (100ms+). G1 and ZGC do concurrent old-gen collection to reduce pause times. Interviewer question: 'Why is generational GC efficient?' Because most objects die young — cost is proportional to live objects, not total allocations.
7. Explain synchronized vs ReentrantLock. Intermediate
synchronized is a JVM-level lock: implicit acquire/release, unfair, no interruptibility, no tryLock. ReentrantLock is a library class: same lock semantics but you can tryLock with timeout, lockInterruptibly, and construct it as fair. Fair lock = FIFO wait queue (slower, no starvation). Prefer synchronized for simple critical sections; reach for ReentrantLock when you need tryLock, fairness, or interrupt handling.
8. What is a functional interface? Intermediate
An interface with exactly one abstract method. @FunctionalInterface annotation enforces this at compile time. Lambdas and method references target functional interfaces. Standard functional interfaces live in java.util.function: Function<T,R>, Consumer<T>, Supplier<T>, Predicate<T>, BiFunction<T,U,R>. Interviewer follow-up: 'Can a functional interface have default methods?' Yes — only the abstract method count matters.
9. Explain Streams and when NOT to use them. Intermediate
Streams are declarative pipelines: filter, map, reduce, collect. Lazy evaluation until terminal operation. Parallel streams use ForkJoinPool.commonPool() by default. Do NOT use streams when: (1) you need to throw checked exceptions from the lambda, (2) you need to modify external state (breaks laziness), (3) the pipeline has fewer than ~1000 elements and iteration overhead dominates work, (4) the operation is fundamentally imperative (early exit with a complex condition).
// Idiomatic stream
Map<String, Long> byDept = employees.stream()
.filter(e -> e.salary > 100_000)
.collect(groupingBy(Employee::department, counting()));
10. What is dependency injection? Intermediate
DI is the pattern where an object receives its dependencies from outside rather than constructing them itself. Constructor injection (preferred) makes dependencies explicit and enables final fields. Field injection (@Autowired on fields) is easier but hides dependencies and blocks immutability. Setter injection is for optional dependencies. In Spring, the IoC container reads @Component / @Service and wires beans at startup.
11. Explain Spring bean scopes. Intermediate
singleton (default) — one instance per Spring context. prototype — new instance per injection. request / session / application — web-scoped. Bug pattern: injecting a prototype bean into a singleton bean — you get the same prototype instance forever unless you use @Lookup or ObjectFactory. Test the wiring in Spring Boot with @SpringBootTest.
12. What is the Optional class and when to use it? Intermediate
Optional<T> is a container that either holds a value or represents absence — a typed alternative to null. Best use: return type of methods that may not have a result. Do NOT use Optional as a field type or method parameter — it's not Serializable and it obscures intent. Common mistake: calling .get() without .isPresent() — same NullPointerException you were trying to avoid.
// Idiomatic
public Optional<User> findByEmail(String email) { ... }
repo.findByEmail(input)
.map(User::getName)
.orElse("unknown");
Advanced questions
13. What is the Java Memory Model? Advanced
The JMM defines when one thread's writes become visible to another thread. Without synchronization or volatile, the compiler and CPU can reorder loads/stores — you can see stale values or writes out of order. volatile guarantees visibility (write happens-before subsequent read of the same variable). synchronized guarantees visibility AND atomicity. java.util.concurrent primitives build on this. Interviewer test: write a lock-free counter without volatile, ask why it fails on multi-core.
14. What happens when you call new Thread().start() a thousand times? Advanced
Each thread takes ~1MB stack space by default. A thousand threads = ~1GB of stack. OS scheduling starts to dominate — context-switch cost swamps useful work. On JVMs before Loom, the answer is 'use an ExecutorService with a bounded pool.' On Java 21+ with virtual threads, spawn a million — the JVM multiplexes them onto a small carrier-thread pool. Interviewer test: know which JVM you're on before answering.
15. How does CompletableFuture work? Advanced
CompletableFuture is a promise with a chainable API. thenApply — transform result. thenCompose — flatMap for nested futures. thenCombine — join two futures. exceptionally — recover. Executed on ForkJoinPool.commonPool() by default — for I/O work, pass your own Executor. Common bug: forgetting join() at the end of a chain, so the main thread exits before the async work completes.
16. Explain the volatile keyword. Advanced
volatile on a field guarantees: (1) reads and writes go to main memory, not thread-local cache, (2) reads see the most recent write from any thread (happens-before), (3) no compiler reordering across the volatile access. It does NOT guarantee atomicity of compound operations — volatile int counter; counter++ is still a race. Use AtomicInteger for atomic increments.
17. What is a classloader? Advanced
The JVM component that loads .class files into memory. Three built-in loaders: bootstrap (rt.jar / JDK core), platform (extension classes), app/system (your classpath). Delegation model — a classloader asks its parent first, only loads the class itself if the parent can't. Custom classloaders enable plugin systems and hot-reloading (Tomcat, OSGi). Interviewer trick: 'Can two classes with the same name coexist?' Yes, if loaded by different classloaders — the identity is (loader, name).
18. How would you tune a Java app that hits a GC pause every 30 seconds? Advanced
Enable GC logs first (-Xlog:gc*:file=gc.log). Look for young vs old GC frequency and duration. If old GC is triggered often, the heap is too small OR you have an object retention leak. Increase -Xmx if working set is legitimately large. Switch to G1 (default in modern JVMs) or ZGC for sub-10ms pauses. Profile with async-profiler or JFR to find allocation hotspots. Never blindly increase heap — it postpones the problem.
Common mistakes candidates make
- Not overriding hashCode() when you override equals() — breaks HashMap/HashSet.
- Using synchronized on a Boolean or String literal — those are interned, you're locking on a shared object.
- Autoboxing in tight loops — Integer allocation per iteration murders performance.
- Catching Exception instead of the specific type — hides bugs.
- Assuming HashMap iteration order is stable across JVM versions — it's not (until you use LinkedHashMap).
Study strategy
Two-week plan. Week 1: rebuild HashMap, ConcurrentHashMap, and ArrayList from scratch in a scratch project — you learn more from one implementation than 10 blog posts. Week 2: read Java Concurrency in Practice chapters 1-6, then solve LeetCode Java-flagged problems for one hour per day. Before your interview, review the JMM section — it's the single most-asked advanced topic and the one candidates fake worst.
Do timed mocks with MiPrep before the real thing
Upload your resume and target job description. MiPrep generates a rehearsed answer set in your voice from your own projects — so mock interviews sound like real ones.
Get MiPrep — free 🔒 Interview audio is never stored on our servers