Backend & full-stack candidates
Java Interview Questions
Java interviews test fundamentals, the memory model, collections, concurrency, and modern language features. Each question below gives a concise explanation, the trade-off interviewers probe, and the follow-up they usually ask. Then you can drill any of them in a scored MockWise interview.
- Grouped by difficulty
- Answer + trade-off + follow-up
- Practice as a scored interview
How to use this hub
- Each entry carries the full answer anatomy: explanation, why interviewers ask it, the common misconception, the trade-off sentence, and the follow-up that arrives next. Code included where seeing beats reading.
- Loop: read the answer, say a 60-90 second version out loud without looking, run it in a technical mock, re-drill whichever ones the report marks.
- Level tags are the ladder: Beginners must own the basics before touching Advanced; clearing a level is defined as surviving its follow-ups cold, not recognizing the answers.
- The Java-specific trap is vocabulary without mechanism. Every entry below names the mechanism the follow-up will ask for.
What Java loops probe, by level
Junior
OOP contracts (equals/hashCode, interfaces vs abstract classes), Strings (immutability, pool, StringBuilder), collections at the usage level, exceptions basics. The bar is precise definitions plus one example each. No JVM depth expected, but no fumbling basics tolerated.
Mid
Collections internals (HashMap lifecycle, ConcurrentHashMap semantics), concurrency vocabulary in motion (volatile, atomics, thread pools), Optional/streams fluency, memory model awareness (what leaks, how you found it). Follow-ups go operational: at what size does this hurt?
Senior
JVM behavior under load (GC choices, tiered compilation and warmups, jlink/container sizing), incident stories with metrics, concurrency design (where locks lose), and modern-language judgment (records, sealed types, pattern matching as design tools, not trivia).
The answer shape that scores
- Definition in one precise sentence, then mechanism: what actually happens in memory, on the heap, in the runtime.
- One trade-off or failure mode unprompted: where this thing hurts (O(n) chain, O(n^2) concat loop, cache miss storm).
- A production sentence: the tool, metric, or incident that proves you have operated it, not memorized it.
- Stop at 60-90 seconds and take the follow-up; rambling answers about Java read as uncertainty about Java.
Example questions and ideal structure
What is the difference between == and .equals() for Strings?
== compares references (same object or not); .equals() compares character content. Two equal strings can be separate objects, so == may be false while .equals() is true.
String a = new String("java");
String b = new String("java");
System.out.println(a == b); // false
System.out.println(a.equals(b)); // trueWhy it matters: Most Java interviews open here to check you understand reference vs value semantics.
Common mistake: The string pool makes == true for literals, which tricks people into thinking == is a value compare.
Trade-off: Prefer .equals(), or Objects.equals() for null-safety; never rely on == for text.
Follow-up to expect: Why do two equal String literals sometimes compare equal with ==?
How does a HashMap work internally?
Keys are hashed, spread, and masked into a bucket. Collisions chain as a linked list; Java 8 treeifies a long chain into a red-black tree, and the table doubles and rehashes once size crosses capacity x load factor.
// bucket index = (n - 1) & spread(hash)
// chain length > 8 -> treeify (table >= 64)
// size > capacity * 0.75 -> resize x2, rehashCommon mistake: Lookup is O(1) only on average. A poor hashCode that clusters keys degrades it toward O(n).
Trade-off: HashMap is not thread-safe; use ConcurrentHashMap for concurrent access instead of locking the whole map.
Follow-up to expect: What happens if every key has the same hashCode?
When do you use checked vs unchecked exceptions?
Checked exceptions force callers to handle recoverable, expected conditions; RuntimeExceptions are unchecked and are the modern default in Spring/service code because they compose with lambdas and keep APIs clean.
Why it matters: Interviewers use it to see whether you design APIs or just sprinkle catches.
Common mistake: More checked exceptions means safer code. They leak low-level failures through every layer.
Trade-off: Wrap third-party checked exceptions at the boundary into a domain RuntimeException with context.
Follow-up to expect: Why does Spring translate SQLException into DataAccessException?
What is the difference between final, finally, and finalize()?
final fixes a variable reference or blocks overriding; finally always runs (except on System.exit) and is mostly replaced by try-with-resources; finalize() is deprecated for removal and must not be used for cleanup.
final List<String> xs = new ArrayList<>();
xs.add("ok"); // allowed: reference fixed, not contents
// xs = new ArrayList<>(); // compile errorCommon mistake: final makes an object immutable. It fixes the reference, not the object state.
Trade-off: Use try-with-resources for cleanup and java.lang.ref.Cleaner for native resources.
Follow-up to expect: If final fixes the reference, why can you still add to a final List?
ArrayList vs LinkedList: which do you actually pick?
In practice ArrayList wins almost everywhere: it is a contiguous, cache-friendly array with amortized O(1) append. LinkedList pays per-node allocation and pointer-chasing, and even its "O(1)" insert requires walking to the node first.
Common mistake: LinkedList is faster for inserts/removes. Reaching position i is O(n), so add(i, x) is not faster.
Trade-off: For stack/queue semantics use ArrayDeque, not LinkedList or the legacy Stack.
Follow-up to expect: When does LinkedList structure genuinely help?
How is ConcurrentHashMap safer and faster than a synchronized HashMap?
Collections.synchronizedMap locks the entire map. ConcurrentHashMap reads are lock-free (volatile values) and writes lock only the affected bin, using CAS when a bucket is absent, so reads stay concurrent and writes parallelize across buckets.
Why it matters: Concurrency depth separates mid-level from senior candidates.
Common mistake: size() and iteration are weakly consistent. You can read a stale count, which is usually fine but is not a snapshot.
Trade-off: It does not make compound actions atomic; use compute/merge/computeIfAbsent for check-then-act.
Follow-up to expect: How would you build an atomic counter with no lost updates?
What breaks if you override equals() but not hashCode()?
HashMap/HashSet bucket by hashCode() and only then confirm with equals(). If equal objects return different hashes, the lookup can land in the wrong bucket, so get()/contains() returns false even though equals() matches.
Map<Point,String> m = new HashMap<>();
m.put(new Point(1,2), "p");
m.get(new Point(1,2)); // null unless hashCode is overridden tooCommon mistake: equals is enough because it finds the match. But equals() never runs if the hash points elsewhere.
Trade-off: Records generate both methods for free; otherwise derive both from the same immutable fields.
Follow-up to expect: Why must hashCode stay stable while an object is a map key?
orElse vs orElseGet: what does the evaluator check?
orElse’s argument is evaluated eagerly even when the value exists; orElseGet runs the supplier only when empty. The distinction scales into the whole Optional discipline: map/flatMap/filter chains that keep absence composable, and the anti-patterns (get() without isPresent, Optional fields, Optional parameters, Optional<List>).
order.find(id)
.map(Order::total)
.orElseGet(() -> priceService.recompute(id)); // only runs when emptyWhy it matters: It is the cheapest filter question for “does this person actually use Optional or just recognize the word.”
Common mistake: That orElse is just a shorter spelling. A lazily-expensive default (a DB call, a log line) fires on every present-value path.
Trade-off: Optional is a return-type tool; fields and parameters stay nullable-friendly or overloaded. Saying the boundary out loud is the senior part of the answer.
Follow-up to expect: Why not Optional<List<T>>: and what do you return instead?
What is type erasure, and what does it forbid you from doing?
Generics exist at compile time and erase to raw types in bytecode: no new T(), no T.class, no instanceof List<String>, no overloads differing only in type arguments, no generic arrays. Workarounds are Class<T> tokens and captured supertypes (Jackson TypeReference).
Why it matters: It tests whether generics are understood as a type-system decision or a syntax feature; the follow-up ladder (why not reified, arrays vs lists) is all mechanism.
Common mistake: That erasure is a bug rather than the compatibility bargain it was. And that reified generics are free.
Trade-off: Arrays are covariant and runtime-checked (ArrayStoreException); generics are invariant and compile-time checked. Collections beat arrays exactly because of this.
Follow-up to expect: Explain PECS: when ? extends and when ? super?
What do records generate, and when is immutability only shallow?
Records generate the canonical constructor, accessors, equals/hashCode/toString from components. Immutable data carriers with real identity-by-value. Immutability is shallow: a record holding a List still has a mutable list unless the compact constructor does List.copyOf.
Why it matters: Modern-Java fluency signal: it also opens the door (interviewers steer there) to compact-constructor validation and pattern matching in switch.
Common mistake: Records as JPA entities (they are not. No proxying/no-arg story) or as enums’ successor; and that final fields alone mean deep immutability.
Trade-off: The right shape is DTO/value object/map key; anything needing inheritance, mutation, or lazy build stays a class or builder.
Follow-up to expect: Where do you put validation in a record, and what does the compact constructor let you normalize?
How to prepare
- Lead with the precise definition, then the memory/threading nuance. That is what moves a mid answer to senior.
- For every collection or concurrency claim, name the trade-off and the failure case the interviewer is probing.
- Drill the topic you fumble in a MockWise technical interview and read the missed points before retrying.
- Say every answer out loud at 60 to 90 seconds before moving to the next entry. Recognition is not the skill being graded.
- Keep a version line for each topic: what changed (Java 8 lambdas, 10 var, 16 records, 17 sealed) signals current maintainership, not nostalgia.
FAQs
Are these real interview questions?
They are common Java topics used as practice prompts. MockWise is not affiliated with any company and does not guarantee specific questions are asked.
How do I practice these out loud?
Start a technical interview on MockWise. It adapts follow-ups to your resume stack and scores your reasoning, not just the final answer.
Which Java version should I quote?
Your production version, plus awareness of what your company does not use yet. Quoting a feature nobody on the team runs scores as tutorial, not experience.
Do I need Spring and Hibernate here?
Framework questions appear at mid/senior loops as their own family. This hub keeps the language core; add the stack (Spring Boot, JPA) in the job description or additional instructions so the mock blends both.
Ready to practice?
Practice your answers in a mock interview, then review the transcript-based feedback.
Related practice
Technical Interview Practice
Practice technical interviews: HashMap vs ConcurrentHashMap, rate limiter design, and Java debugging, with trade-off scoring.
Software Engineer Mock Interviews
SDE loop practice: DS/algo + system trade-offs + behavioral in one interview, with a report of missed points.
SQL Interview Questions
Curated SQL interview questions with explanations, performance trade-offs, and follow-ups: joins to window functions.
Last updated: 2026-09-03 · Questions? Contact support · Security