Top 50 Java Interview Questions with Answers (2026): Fresher to Java Expert

Java remains the dominant language for enterprise software, Android development, and backend systems at scale. Interviewers at top tech companies use Java questions to evaluate a candidate's true depth — because you cannot fake your way through the JVM memory model, garbage collection semantics, autoboxing pitfalls, and the internals of the Java Collections Framework.
This guide covers all 50 interview questions across Java memory fundamentals (heap vs stack, GC, pass-by-value, wrapper classes, String vs StringBuilder), the entire Java Collections Framework (HashMap internals, TreeMap, ArrayList resizing, Comparable vs Comparator), data structure implementation in Java (linked lists, stacks, queues, ArrayDeque, trees, heaps, graphs), and advanced algorithmic paradigms (BFS/DFS, Union-Find, Dijkstra, DP, memoization, sliding window, backtracking, lambda sort, bit tricks).
Every answer includes a “💡 Why Interviewers Ask This” insight so you know exactly what is being tested — not just what the answer is.
Contents
- 1.Java Memory & Core Fundamentals (Q1–Q7)Pointers vs References · Pass-by-Value · Garbage Collection · Array vs ArrayList · Wrapper Classes · String vs StringBuilder · equals() vs ==
- 2.Java Collections Framework (Q8–Q14)JCF · List vs Set vs Map · HashMap internals · HashMap vs TreeMap · ArrayList resizing · Comparable vs Comparator · Collections.sort()
- 3.Linked Lists & Arrays (Q15–Q20)ListNode · ArrayList vs LinkedList · Reverse LL · Cycle Detection · Find Middle · Doubly Linked List
- 4.Stacks, Queues & Deques (Q21–Q27)Stack LIFO · Legacy Stack · Queue FIFO · Queue instantiation · ArrayDeque · Queue from Stacks · Monotonic Stack
- 5.Trees, BSTs & Tries (Q28–Q34)TreeNode · BST properties · DFS traversals · BFS level-order · AVL vs Red-Black · Trie · LCA in BST
- 6.Heaps, Graphs & Search (Q35–Q42)Heap · PriorityQueue · Adjacency List · BFS · DFS · Union-Find · Dijkstra · Topological Sort
- 7.Algorithmic Paradigms (Q43–Q50)DP · Memoization · Sliding Window · Backtracking · Lambda sort · int[] vs ArrayList<> for DP · Power of 2 bit trick · Deque over LinkedList
- 8.Common Interview MistakesPass-by-value trap · == vs .equals() · String immutability · HashMap thread safety
- 9.Expert Interview StrategyJava 17/21 features · Collections complexity · JVM internals · Design patterns
- 10.Real-World Job ApplicationsBackend Engineer · Android Developer · Platform Engineer
Java Memory & Core Fundamentals Interview Questions (Q1–Q7)
1. Are there Pointers in Java?
Java has no explicit pointers. Instead, it uses References — variables that hold a reference to an object on the JVM heap. Unlike C/C++, you cannot perform pointer arithmetic, access raw memory addresses, or dereference a memory location directly. The JVM manages all memory addressing internally.
- C++ Pointer:
int* ptr = &x;— stores the exact hardware address, supports arithmetic (ptr++) - Java Reference:
MyClass obj = new MyClass();— holds an opaque reference managed by the JVM, no arithmetic allowed
💡 Why Interviewers Ask This: Tests understanding of the JVM memory model abstraction. Java's elimination of raw pointers is the primary reason it eliminates entire classes of bugs: buffer overflows, dangling pointers, and memory corruption — all endemic to C/C++.
2. Is Java Pass-by-Value or Pass-by-Reference?
Java is strictly Pass-by-Value — always. This is the #1 Java trick question in interviews. The confusion arises because:
- Primitives: Pass a copy of the value itself. Modifying it inside the method does NOT change the original
- Objects: Pass a copy of the reference (the memory address). You CAN modify the object's fields via this copied reference, but reassigning the reference itself does NOT affect the original
void modify(int x) { x = 99; } // original unchanged
void modifyObj(Node n) { n.val = 99; } // object mutated ✓
void reassign(Node n) { n = new Node(99); } // original unchanged
int a = 5; modify(a); // a is still 5
Node node = new Node(1); modifyObj(node); // node.val = 99
reassign(node); // node.val is STILL 99, not a new Node💡 Why Interviewers Ask This: Many candidates believe Java passes objects by reference. Understanding that Java copies the value of the reference explains why you can mutate an object through a parameter but cannot replace it with a new object entirely.
3. How does Garbage Collection impact DSA in Java?
Java's Garbage Collector (GC) automatically reclaims heap memory for objects with no remaining references. You never call free() or delete. DSA implications:
- Linked List deletion: Setting
head = nulldrops the reference — GC reclaims the entire list - Memory leak risk: Unused HashMap entries (where the key is still referenced by other code) will NOT be collected. In-memory caches built with HashMap can leak memory even in Java
- GC pauses: In low-latency systems (trading, gaming), GC stop-the-world pauses are a real concern — use primitive arrays over object collections where possible
💡 Why Interviewers Ask This: GC is not a free lunch. Performance-conscious developers know that excessive object creation (autoboxing in loops, creating new strings in loops) increases GC pressure and can cause latency spikes in production systems.
4. What is the difference between Array and ArrayList?
- Array (
int[] arr): Fixed size set at creation. Can store primitives directly (int,char, etc.). O(1) random access. No utility methods - ArrayList (
ArrayList<Integer>): Dynamically resizable. Can only store Objects (requires Wrapper types for primitives). Provides.add(),.remove(),.size(),.contains(). Backed by a resizable array internally
int[] fixed = new int[5]; // Fixed capacity: 5 ArrayList<Integer> dynamic = new ArrayList<>(); // Grows automatically dynamic.add(1); dynamic.add(2); dynamic.add(3); System.out.println(dynamic.size()); // 3
💡 Why Interviewers Ask This: DSA problems requiring dynamic size (unknown number of BFS level nodes, building adjacency lists) need ArrayList. But DP cache arrays where size is known upfront should use primitive int[] for performance — no autoboxing overhead.
5. What are Wrapper Classes and Autoboxing?
The Java Collections Framework cannot store primitive types (int, double, etc.) — only Objects. Wrapper Classes (Integer, Double, Character, etc.) wrap primitives inside an Object. Autoboxing is the compiler automatically converting a primitive to its wrapper and back.
// Autoboxing: int → Integer (automatic)
List<Integer> list = new ArrayList<>();
list.add(42); // Compiler converts: list.add(Integer.valueOf(42));
// Unboxing: Integer → int (automatic)
int x = list.get(0); // Compiler converts: list.get(0).intValue();
// ❌ DANGER: Autoboxing in a tight loop
for (int i = 0; i < 1_000_000; i++) {
list.add(i); // Creates 1 MILLION Integer objects on the heap!
}💡 Why Interviewers Ask This: Autoboxing hides performance costs. Creating millions of Integer objects in a loop massively increases GC pressure. This is why high-performance Java DSA code uses int[] arrays for DP caches instead of ArrayList<Integer>.
6. What is the difference between String, StringBuilder, and StringBuffer?
- String: Immutable. Every modification (
+,concat()) creates a new String object on the heap. Building a string in a loop with+is O(n²) total — catastrophic for large inputs - StringBuilder: Mutable, not thread-safe. O(1) amortized
append(). The standard choice for all string building in single-threaded code and interviews - StringBuffer: Mutable, thread-safe (all methods synchronized). Slower than StringBuilder due to lock overhead. Use only in multi-threaded contexts
// ❌ O(n²): creates n intermediate String objects String result = ""; for (String s : words) result += s; // ✅ O(n): one mutable buffer, toString() at the end StringBuilder sb = new StringBuilder(); for (String s : words) sb.append(s); String result = sb.toString();
💡 Why Interviewers Ask This: String concatenation in a loop is one of the most common Java performance bugs. It causes quadratic time complexity for a task that should be linear. Any Java role interview will test whether you know to use StringBuilder.
7. What is the difference between equals() and == in Java?
==: Compares memory references (are these two variables pointing to the exact same object?). For primitives, compares values directly.equals(): Compares content/value (are these two objects logically equivalent?). Overridable — String, Integer, etc. override it to compare by content
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2); // false — different objects
System.out.println(s1.equals(s2)); // true — same content
// String pool interning — another common trick question:
String s3 = "hello"; // from String pool
String s4 = "hello"; // same pool reference
System.out.println(s3 == s4); // true (same pool object)💡 Why Interviewers Ask This: Using == to compare String values is one of the most common Java bugs in production. The String pool interning further confuses candidates who test with literals and assume == always works for Strings.
Java Collections Framework (JCF) Interview Questions (Q8–Q14)
8. What is the Java Collections Framework (JCF)?
The Java Collections Framework is a unified architecture of interfaces and implementations for storing and manipulating groups of objects. Core interfaces include:
- List: Ordered sequence, allows duplicates (
ArrayList,LinkedList) - Set: No duplicates (
HashSet,TreeSet) - Map: Key-value pairs, unique keys (
HashMap,TreeMap) - Queue / Deque: FIFO/double-ended (
LinkedList,ArrayDeque,PriorityQueue)
💡 Why Interviewers Ask This: Re-implementing sorted maps or hash tables from scratch in an interview wastes time. You must know which JCF collection to reach for and justify your choice with its Big-O complexity characteristics. This is expected knowledge for any Java role.
9. What is the difference between List, Set, and Map in Java?
- List: Ordered collection (maintains insertion order), allows duplicates. Use for sequential data, BFS queues, result lists. Key:
ArrayList - Set: Unordered collection, no duplicates. Use for membership testing, de-duplication. Key:
HashSet(O(1) average),TreeSet(sorted, O(log n)) - Map: Maps unique keys to values. Use for frequency counting, memoization, graph adjacency maps. Key:
HashMap(O(1) average),TreeMap(sorted keys, O(log n))
💡 Why Interviewers Ask This: Every two-sum, frequency counting, and sliding window problem uses HashMap. Every graph problem uses either HashMap or adjacency lists. You must know which interface to use before writing a single line.
10. How does HashMap work internally?
HashMap uses an array of “buckets”. Each key's hashCode() determines the bucket index. Multiple keys mapping to the same bucket is a collision — handled by a linked list at that bucket.
- Java 8+ optimization: When a bucket exceeds 8 entries, the linked list is converted to a Red-Black Tree (O(n) → O(log n) per bucket operation)
- Load factor: Default 0.75. When 75% of buckets are filled, the HashMap resizes to double capacity and rehashes all entries
- hashCode() must be consistent with equals(): If two objects are equal, they MUST have the same hashCode — a contract all Java objects must follow
💡 Why Interviewers Ask This: This is the most frequently asked HashMap question at FAANG. Understanding the Red-Black Tree bucket optimization, load factor, and the hashCode/equals contract separates candidates who use HashMap from candidates who understand it.
11. What is the difference between HashMap and TreeMap?
- HashMap: Hash table implementation. No ordering of keys. O(1) average for get/put/remove. Default choice for fast key-value lookups
- TreeMap: Red-Black Tree implementation. Keys stored in ascending sorted order. O(log n) for all operations. Provides useful range methods:
floorKey(),ceilingKey(),subMap()
// Use TreeMap when you need sorted keys
TreeMap<Integer, String> tm = new TreeMap<>();
tm.put(3, "c"); tm.put(1, "a"); tm.put(2, "b");
System.out.println(tm); // {1=a, 2=b, 3=c} — sorted!
// Powerful range queries:
System.out.println(tm.firstKey()); // 1
System.out.println(tm.floorKey(2)); // 2 (largest key <= 2)
System.out.println(tm.ceilingKey(2)); // 2 (smallest key >= 2)💡 Why Interviewers Ask This: Choosing HashMap when you need sorted keys (or TreeMap when you need O(1) access) signals poor awareness of collection performance. TreeMap's range methods are uniquely powerful for calendar, scheduling, and interval problems.
12. How does ArrayList resize dynamically?
When an ArrayList reaches its capacity, it:
- Allocates a new array at 1.5× the current capacity (specifically:
newCapacity = oldCapacity + (oldCapacity >> 1)) - Copies all existing elements via
Arrays.copyOf()— O(n) operation - Discards the old array (becomes eligible for GC)
- Appends the new element to the new array
The amortized cost of each add() is O(1). Use new ArrayList<>(n) to pre-allocate capacity when you know the size upfront, eliminating all reallocations.
💡 Why Interviewers Ask This: Tests knowledge of amortized time complexity. While a specific resize is O(n), the amortized cost per add over n insertions is O(1). Java uses 1.5×, while C++ vector uses 2× — knowing the Java-specific ratio shows deep JDK familiarity.
13. What is the difference between Comparable and Comparator?
- Comparable: Defines the natural ordering of a class. Implemented by the class itself by overriding
compareTo(T other). E.g.,Integer,Stringimplement Comparable - Comparator: Defines a custom ordering outside the class, via
compare(T o1, T o2). Use when you don't own the class or need multiple different sort orders
// Comparable — defined inside the class
class Student implements Comparable<Student> {
int grade;
public int compareTo(Student other) {
return Integer.compare(this.grade, other.grade);
}
}
// Comparator — defined externally (lambda syntax)
PriorityQueue<int[]> maxHeap = new PriorityQueue<>(
(a, b) -> b[0] - a[0] // reverse order = max-heap
);💡 Why Interviewers Ask This: You NEED Comparator to create a Max-Heap with PriorityQueue (Java's PriorityQueue is min-heap by default). Every Top-K problem, Dijkstra with custom objects, and interval-sort problem requires Comparator.
14. How does Collections.sort() work internally?
Collections.sort() uses Timsort — a hybrid of Merge Sort and Insertion Sort. Key properties:
- Stable sort: Preserves the relative order of equal elements (critical for multi-key sorting)
- O(n log n) worst case — unlike QuickSort which degrades to O(n²)
- Arrays.sort() for primitives uses Dual-Pivot Quicksort — not stable but faster in practice for primitives
- Arrays.sort() for Objects also uses Timsort (stable)
💡 Why Interviewers Ask This: Knowing that Collections.sort() is stable and O(n log n) worst-case (not average-case like QuickSort) proves you understand when stability matters — e.g., first sort by department then by salary while keeping department order.
Linked Lists & Arrays Interview Questions (Q15–Q20)
15. How do you declare a Linked List Node in Java?
class ListNode {
int val;
ListNode next;
ListNode(int val) {
this.val = val;
this.next = null;
}
}
// Usage:
ListNode head = new ListNode(1);
head.next = new ListNode(2);
head.next.next = new ListNode(3);
// 1 → 2 → 3 → null💡 Why Interviewers Ask This: This is the exact ListNode definition used on LeetCode Java problems. You must be able to write this from memory in a live interview. Unlike C++, there is no constructor initializer list syntax — use explicit this.field = value assignment in the constructor body.
16. What is the difference between ArrayList and LinkedList in Java?
- ArrayList: Backed by a dynamic array. O(1) random access by index. O(n) insert/delete in the middle (element shifting). Cache-friendly — contiguous memory
- LinkedList: Doubly linked nodes. O(n) random access (must traverse from head). O(1) insert/delete at a known node. Each node has
nextandprevpointers — higher memory overhead per element
In practice: ArrayList is preferred for almost all use cases due to better cache locality. LinkedList is only preferred when you need frequent insertions/deletions at the front (use ArrayDeque instead for that).
💡 Why Interviewers Ask This: Many candidates say “LinkedList is faster for insertions” — but forget that finding the insertion point is still O(n). ArrayList is also much more CPU-cache-friendly since its elements are contiguous in memory, making it faster in practice for most workloads.
17. How do you reverse a Linked List in Java?
Use three references: prev, current, and next. Iteratively reverse each node's next pointer:
ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode next = curr.next; // 1. Save next
curr.next = prev; // 2. Reverse the link
prev = curr; // 3. Advance prev
curr = next; // 4. Advance curr
}
return prev; // prev is the new head
}💡 Why Interviewers Ask This: This is the “Hello World” of pointer/reference manipulation. It tests that you can track multiple moving references simultaneously. Time: O(n), Space: O(1). If you cannot reverse a linked list from memory, the interview typically ends here.
18. How do you detect a cycle in a Linked List?
Use Floyd's Cycle Detection — Tortoise and Hare:
boolean hasCycle(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next; // 1 step
fast = fast.next.next; // 2 steps
if (slow == fast) return true; // cycle detected!
}
return false;
}- Time: O(n) — fast pointer catches slow within at most n steps
- Space: O(1) — only two extra references, no HashSet needed
- HashSet approach: O(n) space — suboptimal, not the expected answer
💡 Why Interviewers Ask This: The most elegant linked list algorithm. A candidate who immediately answers “HashSet approach” shows surface-level knowledge. Floyd's algorithm with O(1) space shows mastery. Interviewers will specifically ask for the O(1) space solution.
19. How do you find the middle of a Linked List in one pass?
ListNode findMiddle(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next; // 1 step
fast = fast.next.next; // 2 steps
}
return slow; // slow is at the middle!
}
// For even-length list (1→2→3→4): returns node 3 (second middle)
// For odd-length list (1→2→3→4→5): returns node 3 (exact middle)💡 Why Interviewers Ask This: The two-pass approach (count length n, traverse to n/2) makes two complete passes. Tortoise and Hare finds the middle in ONE pass using O(1) extra space. It is directly used as a sub-problem in Merge Sort on Linked Lists.
20. What is a Doubly Linked List and when do you use it?
A Doubly Linked List is a linked list where each node has both a next and a prev pointer, enabling O(1) traversal and deletion in both directions.
class DNode {
int val;
DNode next, prev;
DNode(int val) { this.val = val; }
}- LRU Cache implementation: The core backing structure. Moving a recently-used node to the front requires O(1) with a doubly linked list — impossible with a singly linked list
- Java's LinkedList: Is a doubly linked list under the hood
- Browser back/forward history: Classic real-world example
💡 Why Interviewers Ask This: The LRU Cache problem (LeetCode #146) combining a Doubly Linked List + HashMap is a canonical FAANG system design coding question. Building the O(1) remove-and-move operation requires the prev pointer.
Stacks, Queues & Deques Interview Questions (Q21–Q27)
21. What is a Stack and when do you use it?
A Stack is a Last-In-First-Out (LIFO) data structure. The last element pushed is the first to be popped.
- push(x): Add to top — O(1)
- pop(): Remove from top — O(1)
- peek(): View top without removing — O(1)
Use cases: Recursive call simulation (iterative DFS), syntax parsing (matching parentheses), undo/redo operations, backtracking problems.
💡 Why Interviewers Ask This: Stacks are the foundation of DFS traversal and recursive problem simulation. Problems with “most recent” or “last seen” in their description are strong signals to reach for a stack.
22. Why is the java.util.Stack class considered legacy?
java.util.Stack extends Vector — an older synchronized collection where every method is synchronized, even in single-threaded code. This causes unnecessary lock acquisition on every push(), pop(), and peek() — a significant performance bottleneck.
// ❌ Legacy: every operation acquires a lock Stack<Integer> stack = new Stack<>(); // ✅ Modern: use Deque as a stack Deque<Integer> stack = new ArrayDeque<>(); stack.push(1); // addFirst — O(1) stack.pop(); // removeFirst — O(1) stack.peek(); // peekFirst — O(1)
💡 Why Interviewers Ask This: A classic Java API design awareness question. The official Javadoc for java.util.Stack itself recommends using ArrayDeque instead. Writing new Stack<>() in an interview signals you are using outdated Java practices.
23. What is a Queue and why is it fundamental to BFS?
A Queue is a First-In-First-Out (FIFO) data structure. The first element enqueued is the first to be dequeued — guaranteeing level-by-level (shortest-path-first) processing.
- offer(x) / add(x): Enqueue at rear — O(1)
- poll() / remove(): Dequeue from front — O(1)
- peek(): View front without removing — O(1)
BFS connection: BFS explores all nodes at distance d before any node at distance d+1. This guarantee is only achievable with FIFO ordering — you process nodes in exactly the order you discovered them.
💡 Why Interviewers Ask This: BFS is the algorithm for finding the shortest path in an unweighted graph. Queue is its core backing data structure. Accidentally using a Stack instead of a Queue turns BFS into DFS, exploring the wrong traversal order entirely.
24. How do you instantiate a Queue in Java?
Queue is an interface in Java — you cannot instantiate it directly. You must use a concrete implementation:
// ✅ Standard for BFS (FIFO queue) Queue<Integer> q = new LinkedList<>(); // ✅ Faster alternative (backed by circular array) Queue<Integer> q = new ArrayDeque<>(); // ✅ Priority Queue (min-heap, NOT FIFO) Queue<Integer> pq = new PriorityQueue<>(); // Usage: q.offer(1); q.offer(2); q.offer(3); System.out.println(q.poll()); // 1 — FIFO System.out.println(q.peek()); // 2 — view front
💡 Why Interviewers Ask This: Many candidates write Queue<Integer> q = new Queue<>() — which will not compile. Queue is an interface. This is one of the most common Java compilation errors in coding interviews. Always declare as the interface, instantiate as the implementation.
25. What is ArrayDeque and why is it preferred?
ArrayDeque is a double-ended queue backed by a resizable circular array. It supports O(1) insert/delete at both front and rear — making it the best implementation for both Stack and Queue operations.
Deque<Integer> dq = new ArrayDeque<>(); // Used as a Stack: dq.push(1); dq.push(2); dq.push(3); // addFirst dq.pop(); // returns 3 (LIFO) — removeFirst // Used as a Queue: dq.offer(1); dq.offer(2); dq.offer(3); // addLast dq.poll(); // returns 1 (FIFO) — removeFirst // Used as a Deque (sliding window maximum): dq.offerFirst(10); // add to front dq.pollLast(); // remove from back
💡 Why Interviewers Ask This: ArrayDeque is the Sliding Window Maximum secret weapon. The monotonic deque pattern needs O(1) operations at BOTH ends — only a Deque can do this. ArrayDeque has no null-check overhead and is significantly faster than LinkedList in practice.
26. How do you implement a Queue using two Stacks?
class MyQueue {
Deque<Integer> s1 = new ArrayDeque<>(); // enqueue stack
Deque<Integer> s2 = new ArrayDeque<>(); // dequeue stack
void push(int x) { s1.push(x); } // O(1)
int pop() {
if (s2.isEmpty()) {
while (!s1.isEmpty()) s2.push(s1.pop()); // transfer
}
return s2.pop(); // O(1) amortized
}
int peek() {
if (s2.isEmpty()) {
while (!s1.isEmpty()) s2.push(s1.pop());
}
return s2.peek();
}
}💡 Why Interviewers Ask This: A classic constraints test — simulating FIFO behavior using only LIFO tools. The lazy transfer pattern (only move elements when s2 is empty) achieves O(1) amortized for all operations. Each element is pushed and popped exactly twice total.
27. What is a Monotonic Stack?
A Monotonic Stack maintains elements in strictly increasing or strictly decreasing order. When a new element violates the ordering, elements are popped until the order is restored.
// Next Greater Element using Monotonic Stack — O(n)
int[] nextGreater(int[] nums) {
int n = nums.length;
int[] res = new int[n];
Arrays.fill(res, -1);
Deque<Integer> stack = new ArrayDeque<>(); // stores indices
for (int i = 0; i < n; i++) {
while (!stack.isEmpty() && nums[stack.peek()] < nums[i]) {
res[stack.pop()] = nums[i]; // Found next greater!
}
stack.push(i);
}
return res;
}💡 Why Interviewers Ask This: The ONLY O(n) solution for “Next Greater Element,” “Daily Temperatures,” and “Largest Rectangle in Histogram.” A brute-force O(n²) nested loop gets TLE on large inputs. Recognizing when to apply a monotonic stack is a senior-level signal.
Trees, BSTs & Tries Interview Questions (Q28–Q34)
28. How do you declare a Binary Tree Node in Java?
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int val) { this.val = val; }
}
// Build a tree: 3
// / \
// 1 5
TreeNode root = new TreeNode(3);
root.left = new TreeNode(1);
root.right = new TreeNode(5);💡 Why Interviewers Ask This: The exact TreeNode definition used on LeetCode Java problems. You must write this from memory. Note: unlike C++, Java does not require explicit null initialization — reference fields default to null automatically.
29. What is a Binary Search Tree (BST)?
A BST is a binary tree where for every node: all values in the left subtree are less than the node, and all values in the right subtree are greater. This ordering enables O(log n) search/insert/delete in a balanced BST.
// BST search — O(log n) for balanced tree
TreeNode search(TreeNode root, int target) {
if (root == null || root.val == target) return root;
if (target < root.val) return search(root.left, target);
return search(root.right, target);
}💡 Why Interviewers Ask This: BST is the foundation of Java's TreeMap and TreeSet (Red-Black BST specifically). The BST invariant enables not just search, but also “find kth smallest,” “range sum,” and “successor/predecessor” queries in O(log n).
30. What are the three DFS traversals of a Binary Tree?
// 1. INORDER (Left → Root → Right) — BST gives ascending sorted order
void inorder(TreeNode node) {
if (node == null) return;
inorder(node.left);
System.out.print(node.val + " ");
inorder(node.right);
}
// 2. PREORDER (Root → Left → Right) — copy/serialize a tree
void preorder(TreeNode node) {
if (node == null) return;
System.out.print(node.val + " ");
preorder(node.left); preorder(node.right);
}
// 3. POSTORDER (Left → Right → Root) — delete tree (process children first)
void postorder(TreeNode node) {
if (node == null) return;
postorder(node.left); postorder(node.right);
System.out.print(node.val + " ");
}💡 Why Interviewers Ask This: Inorder of a BST always gives elements in ascending sorted order — this is a critical property used in “Kth Smallest Element in BST.” Postorder is required for safe tree deletion (must process children before the parent).
31. How do you perform Level-Order BFS on a Binary Tree?
List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if (root == null) return result;
Queue<TreeNode> q = new ArrayDeque<>();
q.offer(root);
while (!q.isEmpty()) {
int size = q.size(); // nodes at this level
List<Integer> level = new ArrayList<>();
for (int i = 0; i < size; i++) {
TreeNode node = q.poll();
level.add(node.val);
if (node.left != null) q.offer(node.left);
if (node.right != null) q.offer(node.right);
}
result.add(level);
}
return result;
}💡 Why Interviewers Ask This: The int size = q.size() snapshot before the inner loop is the key insight — it “freezes” the count of nodes at the current level before adding the next level's children. This pattern solves “Right Side View,” “Maximum Width of Tree,” and “Zigzag Traversal.”
32. What is the difference between AVL Tree and Red-Black Tree?
- AVL Tree: Strictly balanced — height difference between any two subtrees ≤ 1. More rotations needed on insert/delete. Faster lookups (shorter tree). Used in databases where reads vastly outnumber writes
- Red-Black Tree: Loosely balanced using color bits (red/black rules). Fewer rotations on insert/delete. Slightly taller but faster writes. Used in most language standard libraries — Java's
TreeMap,TreeSet, and C++'sstd::map
💡 Why Interviewers Ask This: Java's TreeMap and TreeSet are Red-Black Trees — so every time you use TreeMap, you are using a Red-Black Tree. Understanding why Red-Black Trees were chosen (faster inserts/deletes than AVL) shows knowledge of real-world engineering tradeoffs.
33. What is a Trie and how do you implement it in Java?
class TrieNode {
boolean isEndOfWord = false;
TrieNode[] children = new TrieNode[26];
}
class Trie {
TrieNode root = new TrieNode();
void insert(String word) {
TrieNode cur = root;
for (char c : word.toCharArray()) {
int i = c - 'a';
if (cur.children[i] == null)
cur.children[i] = new TrieNode();
cur = cur.children[i];
}
cur.isEndOfWord = true;
}
boolean search(String word) {
TrieNode cur = root;
for (char c : word.toCharArray()) {
int i = c - 'a';
if (cur.children[i] == null) return false;
cur = cur.children[i];
}
return cur.isEndOfWord;
}
}💡 Why Interviewers Ask This: A Trie provides O(L) search and prefix matching (where L = word length), which HashMap cannot do natively. Powers real-world applications: Google Autocomplete, IDE code completion, spell-checkers, IP routing tables.
34. How do you find the Lowest Common Ancestor (LCA) in a BST?
In a BST, the LCA can be found without visiting all nodes — leverage the BST ordering property:
TreeNode lca(TreeNode root, TreeNode p, TreeNode q) {
if (root == null) return null;
// Both nodes are in LEFT subtree
if (p.val < root.val && q.val < root.val)
return lca(root.left, p, q);
// Both nodes are in RIGHT subtree
if (p.val > root.val && q.val > root.val)
return lca(root.right, p, q);
// One is on each side — current node IS the LCA
return root;
}💡 Why Interviewers Ask This: The BST LCA is O(log n) — far faster than the O(n) general binary tree LCA. The insight is that the first node where p and q are on opposite sides is the LCA. Knowing when a BST property can cut complexity is a FAANG-level optimization signal.
Heaps, Graphs & Search Interview Questions (Q35–Q42)
35. What is a Heap?
A Heap is a complete binary tree satisfying the heap property, stored as a flat array (parent at index i, children at 2i+1 and 2i+2):
- Max-Heap: Parent ≥ both children. Maximum element always at index 0 (root). Fetch max in O(1)
- Min-Heap: Parent ≤ both children. Minimum element at root. Fetch min in O(1)
- insert / poll: O(log n) — maintains heap property via sift-up/sift-down
💡 Why Interviewers Ask This: Heaps power all “find the K largest/smallest” problems, priority-based scheduling, and Dijkstra's algorithm. The array-based storage (no pointers!) gives heaps superior cache performance vs pointer-based trees.
36. How do you create Min-Heap and Max-Heap in Java?
// Min-Heap (default) — smallest element at top
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
minHeap.offer(3); minHeap.offer(1); minHeap.offer(5);
System.out.println(minHeap.peek()); // 1
// Max-Heap — largest element at top
PriorityQueue<Integer> maxHeap =
new PriorityQueue<>(Collections.reverseOrder());
maxHeap.offer(3); maxHeap.offer(1); maxHeap.offer(5);
System.out.println(maxHeap.peek()); // 5
// Custom comparator (e.g., by array element)
PriorityQueue<int[]> pq = new PriorityQueue<>(
(a, b) -> a[0] - b[0] // min-heap on first element
);💡 Why Interviewers Ask This: You will never build a heap from scratch. You ARE expected to use PriorityQueue for Top-K Frequent Elements, Merge K Sorted Lists, K Closest Points, and Dijkstra. The max-heap syntax with Collections.reverseOrder() trips up many candidates who are only familiar with min-heaps.
37. How do you represent a Graph in Java?
// Adjacency List — O(V+E) space (optimal for sparse graphs)
int n = 5; // 5 nodes
List<List<Integer>> adj = new ArrayList<>();
for (int i = 0; i < n; i++) adj.add(new ArrayList<>());
adj.get(0).add(1); // edge 0 → 1
adj.get(0).add(2); // edge 0 → 2
adj.get(1).add(3); // edge 1 → 3
// Weighted graph — store {neighbor, weight} as int[]
List<List<int[]>> wadj = new ArrayList<>();
for (int i = 0; i < n; i++) wadj.add(new ArrayList<>());
wadj.get(0).add(new int[]{1, 5}); // edge 0→1, weight 5💡 Why Interviewers Ask This: Adjacency matrix costs O(V²) memory — prohibitive for large sparse graphs. Adjacency list costs O(V + E) — optimal. Every real-world graph (social networks, road networks) is sparse. Choosing the right representation is the first decision in any graph problem.
38. How do you implement BFS in a Graph in Java?
void bfs(int start, List<List<Integer>> adj, int n) {
boolean[] visited = new boolean[n];
Queue<Integer> q = new ArrayDeque<>();
q.offer(start);
visited[start] = true;
while (!q.isEmpty()) {
int node = q.poll();
System.out.print(node + " ");
for (int neighbor : adj.get(node)) {
if (!visited[neighbor]) {
visited[neighbor] = true;
q.offer(neighbor);
}
}
}
}💡 Why Interviewers Ask This: BFS finds the shortest path in an unweighted graph — guaranteed. The visited[neighbor] = true BEFORE enqueueing (not after dequeueing) is critical: it prevents the same node from being added to the queue multiple times, which would cause exponential blowup in dense graphs.
39. How do you implement DFS in a Graph in Java?
void dfs(int node, List<List<Integer>> adj,
boolean[] visited) {
visited[node] = true;
System.out.print(node + " ");
for (int neighbor : adj.get(node)) {
if (!visited[neighbor]) {
dfs(neighbor, adj, visited);
}
}
}
// Call for all components:
boolean[] visited = new boolean[n];
for (int i = 0; i < n; i++) {
if (!visited[i]) dfs(i, adj, visited);
}💡 Why Interviewers Ask This: DFS is the foundation of connected components, cycle detection, topological sort, and path finding. The outer loop that calls DFS for all unvisited nodes correctly handles disconnected graphs — a common edge case that candidates forget.
40. What is Disjoint Set / Union-Find in Java?
class UnionFind {
int[] parent, rank;
UnionFind(int n) {
parent = new int[n]; rank = new int[n];
for (int i = 0; i < n; i++) parent[i] = i;
}
int find(int x) { // Path compression
if (parent[x] != x) parent[x] = find(parent[x]);
return parent[x];
}
boolean union(int x, int y) { // Union by rank
int px = find(x), py = find(y);
if (px == py) return false; // already same set
if (rank[px] < rank[py]) { int t = px; px = py; py = t; }
parent[py] = px;
if (rank[px] == rank[py]) rank[px]++;
return true;
}
}💡 Why Interviewers Ask This: DSU is required for Kruskal's MST and cycle detection in undirected graphs. With path compression + union by rank, the amortized time per operation is O(α(n)) — nearly O(1). The return false in union when already connected is used to detect cycles in Kruskal's.
41. How do you implement Dijkstra's Algorithm in Java?
int[] dijkstra(int src, List<List<int[]>> adj, int n) {
int[] dist = new int[n];
Arrays.fill(dist, Integer.MAX_VALUE);
dist[src] = 0;
// Min-heap: {distance, node}
PriorityQueue<int[]> pq = new PriorityQueue<>(
(a, b) -> a[0] - b[0]);
pq.offer(new int[]{0, src});
while (!pq.isEmpty()) {
int[] curr = pq.poll();
int d = curr[0], u = curr[1];
if (d > dist[u]) continue; // stale entry
for (int[] edge : adj.get(u)) {
int v = edge[0], w = edge[1];
if (dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
pq.offer(new int[]{dist[v], v});
}
}
}
return dist;
}💡 Why Interviewers Ask This: Dijkstra is the fundamental weighted shortest path algorithm — used in Google Maps, GPS routing, and OSPF network routing. Critical details: initializing dist[] to Integer.MAX_VALUE, the stale entry optimization, and O((V+E) log V) total complexity.
42. What is Topological Sort and when do you use it?
Topological Sort provides a linear ordering of Directed Acyclic Graph (DAG) vertices such that for every directed edge U → V, U appears before V in the ordering.
// Kahn's Algorithm (BFS-based) — uses in-degree
List<Integer> topoSort(int n, List<List<Integer>> adj) {
int[] inDegree = new int[n];
for (int u = 0; u < n; u++)
for (int v : adj.get(u)) inDegree[v]++;
Queue<Integer> q = new ArrayDeque<>();
for (int i = 0; i < n; i++) if (inDegree[i] == 0) q.offer(i);
List<Integer> order = new ArrayList<>();
while (!q.isEmpty()) {
int u = q.poll(); order.add(u);
for (int v : adj.get(u))
if (--inDegree[v] == 0) q.offer(v);
}
return order; // size < n means cycle detected
}💡 Why Interviewers Ask This: Topological Sort solves “Course Schedule” (LeetCode #207/210), build system dependency ordering, and task scheduling. The Kahn's algorithm bonus: if order.size() < n, the graph has a cycle (no valid topological order exists).
Algorithmic Paradigms Interview Questions (Q43–Q50)
43. What is Dynamic Programming (DP)?
DP breaks a complex problem into simpler, overlapping subproblems and stores results to avoid recomputation:
- Top-Down (Memoization): Start from the original problem, recurse, cache results in an array initialized to
-1 - Bottom-Up (Tabulation): Start from base cases, iteratively build up to the final answer using a DP table
// Bottom-up Fibonacci — O(n) vs O(2^n) naive
int fib(int n) {
if (n <= 1) return n;
int[] dp = new int[n + 1];
dp[1] = 1;
for (int i = 2; i <= n; i++)
dp[i] = dp[i-1] + dp[i-2];
return dp[n];
}💡 Why Interviewers Ask This: DP is the most tested hard algorithm at FAANG. The pattern recognition skill — identifying overlapping subproblems — separates candidates who memorize solutions from those who can derive them. Nearly every “optimize for minimum/maximum” problem has a DP solution.
44. How do you implement Memoization in Java?
// Top-Down Memoization — O(n) time, O(n) space
int[] memo = new int[n + 1];
Arrays.fill(memo, -1); // -1 = not yet computed
int fib(int n) {
if (n <= 1) return n;
if (memo[n] != -1) return memo[n]; // cache hit!
return memo[n] = fib(n-1) + fib(n-2); // cache and return
}The sentinel value -1 distinguishes “not yet computed” from a valid answer of 0. For 2D problems, use int[][] memo initialized with -1.
💡 Why Interviewers Ask This: Many candidates initialize memo to 0 and wonder why caching breaks for problems where 0 is a valid answer (e.g., pathfinding where some paths have cost 0). Using -1 as the sentinel is the correct, robust approach.
45. What is the Sliding Window Technique?
// Longest substring without repeating characters — O(n)
int lengthOfLongestSubstring(String s) {
Map<Character, Integer> freq = new HashMap<>();
int left = 0, maxLen = 0;
for (int right = 0; right < s.length(); right++) {
freq.merge(s.charAt(right), 1, Integer::sum); // add char
while (freq.get(s.charAt(right)) > 1) { // shrink
freq.merge(s.charAt(left), -1, Integer::sum);
if (freq.get(s.charAt(left)) == 0)
freq.remove(s.charAt(left));
left++;
}
maxLen = Math.max(maxLen, right - left + 1);
}
return maxLen;
}💡 Why Interviewers Ask This: The O(n) solution for all “find the longest/shortest subarray/substring satisfying a condition” problems. Two nested loops (O(n²)) will TLE on large inputs. Recognizing “substring + window constraint” as Sliding Window is a pattern-recognition skill tested by FAANG.
46. What is Backtracking in Java?
// Generate all permutations — O(n! * n)
void backtrack(int[] nums, List<Integer> curr,
boolean[] used, List<List<Integer>> res) {
if (curr.size() == nums.length) {
res.add(new ArrayList<>(curr));
return;
}
for (int i = 0; i < nums.length; i++) {
if (used[i]) continue;
curr.add(nums[i]); // Choose
used[i] = true;
backtrack(nums, curr, used, res); // Explore
curr.remove(curr.size() - 1); // Undo (backtrack!)
used[i] = false;
}
}💡 Why Interviewers Ask This: The canonical algorithm for Sudoku solving, N-Queens, permutations, combinations, and Word Search. The pattern is always: Choose → Explore → Undo. The critical new ArrayList<>(curr) snapshot prevents all result entries pointing to the same mutable list.
47. How do you sort with a Lambda Comparator in Java?
int[][] intervals = {{1,3},{0,2},{2,4}};
// Sort by end time ascending
Arrays.sort(intervals, (a, b) -> Integer.compare(a[1], b[1]));
// Sort strings by length, then lexicographically
String[] words = {"banana", "fig", "apple"};
Arrays.sort(words, (a, b) -> a.length() != b.length()
? a.length() - b.length()
: a.compareTo(b));
// Sort in descending order
Integer[] nums = {3, 1, 4, 1, 5};
Arrays.sort(nums, (a, b) -> b - a);
// Result: [5, 4, 3, 1, 1]💡 Why Interviewers Ask This: Lambda comparators are required for the Interval Scheduling, Meeting Rooms, and Activity Selection greedy problems. Use Integer.compare(a, b) instead of a - b for safety — a - b overflows when the values are large negative numbers.
48. Why use int[] instead of ArrayList<Integer> for DP caches?
int[] dp: Stores raw primitive values — contiguous array memory, zero boxing overhead, initialized to0by JVM. Direct index access. Blazing fastArrayList<Integer> dp: Stores Integer objects scattered on the heap — autoboxing on every get/set, object header overhead, GC pressure. Vastly slower for numerical DP
// ✅ Fast DP cache — primitive array int[] dp = new int[n + 1]; // o(n) stack-adjacent memory dp[i] = dp[i-1] + dp[i-2]; // ❌ Slow DP cache — avoidable boxed objects List<Integer> dp = new ArrayList<>(); dp.set(i, dp.get(i-1) + dp.get(i-2)); // Hidden autoboxing!
💡 Why Interviewers Ask This: Performance-conscious Java DSA code always uses primitive arrays for DP. In a coding interview under time pressure, int[] is also cleaner to write. This shows awareness of the performance cost of the JCF's object-only constraint.
49. How do you check if a number is a Power of 2 using Bit Manipulation?
boolean isPowerOfTwo(int n) {
return n > 0 && (n & (n - 1)) == 0;
}
// 8 = 1000 → n-1 = 0111 → AND = 0000 ✓
// 12 = 1100 → n-1 = 1011 → AND = 1000 ✗
// 16 = 10000 → n-1 = 01111 → AND = 00000 ✓
// Related trick: count set bits (Brian Kernighan)
int countSetBits(int n) {
int count = 0;
while (n > 0) { n &= (n - 1); count++; }
return count;
}A power of 2 has exactly one 1-bit. Subtracting 1 flips all bits from that position downward. Their AND is always 0. The same n & (n-1) trick removes the lowest set bit — useful for counting set bits.
💡 Why Interviewers Ask This: O(1) hardware time — no loop, no log() call. Tests binary number intuition. The same pattern extends to “Number of 1 Bits,” “Counting Bits,” and “Single Number” (XOR trick) problems.
50. Why prefer ArrayDeque over LinkedList for Queue/Stack in Java?
- LinkedList: Each
offer()allocates a newNodeobject on the heap (object header + pointers + data). For a BFS visiting 100K nodes: 100K heap allocations → massive GC pressure, poor cache locality - ArrayDeque: Backed by a resizable circular array. No per-element object allocation. Contiguous memory = CPU cache-friendly. Significantly faster for all queue/stack operations in practice
// ❌ High GC overhead: new Node per element Queue<Integer> q = new LinkedList<>(); // ✅ Cache-friendly circular array, no GC pressure Queue<Integer> q = new ArrayDeque<>(); Deque<Integer> stack = new ArrayDeque<>(); // ArrayDeque CANNOT contain null elements — use sentinel values if needed
💡 Why Interviewers Ask This: The Java official documentation explicitly recommends ArrayDeque over Stack and LinkedList for both queue and stack use cases. Choosing ArrayDeque signals you have internalized the Java memory model — understanding heap allocation cost is a senior-level insight.
Common Mistakes in Java Interviews
- Saying "Java is pass-by-reference": Java is always pass-by-value. For objects, the reference itself is passed by value — meaning you can modify the object's state but cannot reassign the reference. This is one of the most common interview traps.
- Confusing == with .equals() for Strings:
==checks reference equality (same memory address)..equals()checks content equality. Using==may work with string literals due to the String Pool, but fails withnew String()— always use.equals(). - Not explaining why String is immutable:Simply stating "Strings can't be changed" is incomplete. Explain: String Pool optimization, thread safety, security (class loading, network connections), and caching of hashCode. These reasons show deep understanding.
- Forgetting checked vs unchecked exceptions: Checked exceptions must be caught or declared (
IOException). Unchecked exceptions extendRuntimeException(NullPointerException). Saying "all exceptions must be caught" is wrong and signals shallow Java knowledge. - Claiming HashMap is thread-safe:
HashMapis NOT thread-safe. UseConcurrentHashMapfor concurrent access.Collections.synchronizedMap()is an alternative but less performant. This distinction matters for senior-level interviews. - Ignoring garbage collection when discussing memory:Saying "Java manages memory automatically" without explaining the GC process (mark-and-sweep, generational GC, G1GC) and how to prevent memory leaks (unclosed resources, static references) is insufficient for mid-level+ roles.
Expert Interview Strategy for Java Roles
- Always mention Java version-specific features. Reference records (Java 16), sealed classes (Java 17), pattern matching (Java 21), and virtual threads (Java 21). This shows you stay current, not stuck on Java 8.
- Connect OOP concepts to design patterns. When explaining polymorphism, mention Strategy pattern. For abstraction, reference Factory pattern. Linking concepts to patterns signals architectural thinking beyond textbook definitions.
- Discuss concurrency with real scenarios. Don't just define synchronized — explain when to use
ReentrantLockvssynchronized,CompletableFuturefor async operations, and virtual threads for high-throughput systems. - Know your collections inside out. For every collection question, state time complexity:
ArrayList.get()is O(1),LinkedList.get()is O(n),HashMap.put()is O(1) average. Mention when to useTreeMapvsHashMapvsLinkedHashMap. - Explain JVM internals concisely. Know heap vs stack, method area, classloading, JIT compilation, and garbage collection algorithms. A 30-second JVM overview differentiates you from candidates who only wrote Java code without understanding the runtime.
How These Concepts Apply in Real Java Jobs
Backend Engineer
Uses Spring Boot for REST APIs, manages bean lifecycles with dependency injection, handles concurrency with thread pools for high-traffic services, and optimizes JVM performance with GC tuning for production workloads.
Android Developer
Leverages OOP principles for UI component design, uses interfaces for event callbacks, manages memory carefully to avoid leaks on mobile devices, and applies multithreading for background tasks with coroutines.
Platform / Distributed Systems Engineer
Builds microservices with Spring Cloud, uses ConcurrentHashMap and thread-safe collections for shared state, implements serialization for distributed caching, and configures JVM tuning for low-latency systems.
Conclusion: Master Java Interviews
These 50 Java interview questions cover the essential concepts you'll encounter in backend developer, Android developer, platform engineer, and full-stack Java roles. Mastering these topics demonstrates a solid understanding of Java fundamentals, OOP principles, collections framework, concurrency, JVM internals, and modern Java features.
The key to interview success is understanding the "why" behind each concept — not just memorizing definitions. Each answer includes insights into what interviewers are testing, from core language mechanics to architectural decision-making.
After reviewing these answers, reinforce your learning with hands-on coding practice and review the theory notes. The combination of conceptual understanding + practical coding + theory review creates the strongest foundation for Java interviews.
Topics covered in this guide
Topics in this guide: JVM internals, garbage collection, collections framework (HashMap internals), multithreading, concurrency, OOP principles, stream API.
For freshers: Heap vs stack memory, equals() vs ==, HashMap collision handling, abstract class vs interface, exception handling hierarchy.
For experienced professionals: GC tuning algorithms (G1, ZGC), class loading mechanism, JMM (Java Memory Model) concurrency primitives, thread pools, custom annotations.
Interview preparation tips: Java collections internals (specifically HashMap resize and bucket structure) are frequently tested. Know the new features in Java 8 to 17.
Frequently Asked Questions
Q.What is the most important Java concept to know for interviews?
Q.Should I use LinkedList or ArrayDeque for BFS in Java?
Q.Why is Java String immutable and why does it matter for interviews?
Q.What Java collections are used most frequently in coding interviews?
Q.How important is knowing Dijkstra's algorithm for Java interviews?
Q.What is the difference between fail-fast and fail-safe iterators in Java?
Found these questions helpful? Share them with your peers.
Common Interview Mistakes
Errors that eliminate candidates
- Giving textbook definitions without showing a concrete Java use case.
- Skipping trade-offs and answering as if there is only one correct engineering decision.
- Over-answering for 2-3 minutes without structure, metrics, or outcomes.
Expert Interview Strategy
30-second answer rule
- Start with a one-line definition, then explain one real scenario from Java.
- Use a 3-step structure: concept, practical example, and interviewer intent.
- Close with one trade-off (performance, scale, security, or maintainability).
Real-World Job Applications
These Java patterns are directly tested for production roles where interviewers expect clear debugging steps, architecture trade-offs, and communication under time pressure.
Conclusion
Mastering these Java interview questions means explaining concepts quickly, connecting them to real systems, and justifying decisions with practical trade-offs.
Frequently Asked Questions
How should I prepare this topic in 7 days? Focus on high-frequency patterns, rehearse 30-second answers, and revise one practical example per category.
What do interviewers score most? Clarity, structured thinking, and your ability to reason through constraints and trade-offs.