What interviewers actually check in a Java interview
Java interviews are not a memory test. Interviewers are checking whether you can write correct Java, explain trade-offs, and reason about what happens when code runs at scale. The six things below come up again and again, regardless of the company.
Language fundamentals
JDK vs JRE vs JVM, data types, autoboxing, == vs equals, the hashCode contract, String immutability and the string pool. These are the quick filters.
Object-oriented design
The four pillars, overloading vs overriding, abstract class vs interface (with default and static methods), the role of final, static and access modifiers.
Collections and generics
Choosing between List, Set and Map; ArrayList vs LinkedList; how HashMap works internally; when to use TreeMap or ConcurrentHashMap; fail-fast vs fail-safe iterators.
Modern Java (8 through 21)
Lambdas, functional interfaces, streams, Optional, method references, the new date-time API, records, var, switch expressions and text blocks.
Concurrency and memory
Thread vs Runnable, synchronized vs volatile, ExecutorService, deadlock, the Java memory model, and how garbage collection works at a practical level.
Framework and engineering habits
For Java developer roles in India, basic Spring Boot (IoC, DI, REST controllers, exception handling) plus Git, testing and clean code habits are increasingly part of the interview.
Java interview questions for freshers
These are the questions that come up first in almost every Java fresher interview. They test whether your fundamentals are solid, so answer with a short definition, then one line of why it matters.
Q01 What is the difference between JDK, JRE and JVM? +
JVM is the Java Virtual Machine that executes bytecode. JRE is the JVM plus the standard libraries needed to run Java programs. JDK is the JRE plus the compiler (javac) and development tools like javadoc and jdb.
- You need the JDK to write and compile Java.
- You need only the JRE to run a compiled Java program.
- The JVM is what makes Java platform-independent — the same bytecode runs on any OS that has a JVM.
Q02 Why is Java called platform-independent? +
Java source is compiled to bytecode (a platform-neutral intermediate format), not to native machine code. Any system with a JVM can run that bytecode. This is the "write once, run anywhere" idea.
Q03 What is the signature of the main method, and why is it static? +
The signature is:
public static void main(String[] args)
It is static because the JVM must call it without creating an instance of the class. It is public so the JVM can access it from outside the class. It returns void because nothing is expected back. String[] args holds any command-line arguments.
main methods with different parameter lists, but the JVM only uses the
exact signature above as the entry point.
Q04 What are the primitive data types in Java? +
Java has eight primitive types:
| Type | Size | Example range / value |
|---|---|---|
| byte | 8-bit | −128 to 127 |
| short | 16-bit | −32,768 to 32,767 |
| int | 32-bit | −231 to 231−1 |
| long | 64-bit | −263 to 263−1 |
| float | 32-bit | single-precision decimal |
| double | 64-bit | double-precision decimal |
| char | 16-bit | single Unicode character |
| boolean | JVM-dependent | true / false |
Integer.toUnsignedLong for those cases.)
Q05 What is autoboxing and unboxing in Java? +
Autoboxing is the automatic conversion of a primitive
to its wrapper class (for example int to
Integer). Unboxing is the reverse — a
wrapper object converted back to its primitive type.
Integer a = 100; // autoboxing: int → Integer
int b = a; // unboxing: Integer → int
System.out.println(b + 1); // 101
101
null, the unboxing step tries to call a method on
null and throws NPE. Always null-check wrapper types before unboxing.
Q06 What is the difference between String, StringBuilder and StringBuffer? +
String is immutable — every change creates a new object. StringBuilder is mutable and not thread-safe, used inside a single thread. StringBuffer is mutable and thread-safe (methods are synchronized), used when the same builder is shared across threads.
| Class | Mutable? | Thread-safe? | When to use |
|---|---|---|---|
| String | No | Yes (immutable) | Fixed values, keys, constants |
| StringBuilder | Yes | No | Concatenation inside one thread |
| StringBuffer | Yes | Yes | Concatenation shared across threads |
Q07 Why are strings immutable in Java? +
String immutability gives Java three practical benefits:
- Security — a String used as a file path, class name or database URL cannot be changed after validation.
- Caching — the string pool can safely share identical string literals between parts of the program.
- Thread safety — immutable objects can be shared freely across threads without synchronization.
final,
the internal character array is private final, and no setter modifies
it. Any "modification" returns a new String.
Q08 What is the string pool in Java? +
The string pool is a special area of the heap where Java
stores string literals. When you write
"hello" twice, both references point to the same
pooled object. Strings created with new String(...)
are not pooled unless you call .intern().
String a = "java";
String b = "java";
String c = new String("java");
System.out.println(a == b); // true (same pooled object)
System.out.println(a == c); // false (new object on heap)
System.out.println(a.equals(c)); // true (same characters)
true false true
Q09 What is the difference between == and .equals() in Java? +
== compares references (for objects) or values (for primitives). .equals() compares the logical content of two objects, as defined by the class.
String s1 = "hello";
String s2 = new String("hello");
System.out.println(s1 == s2); // false
System.out.println(s1.equals(s2)); // true
false true
hashCode(). Objects that are equal must return the same hash code, or
hash-based collections will misbehave.
Q10 What is the contract between equals() and hashCode()? +
The contract says: if two objects are equal according to
equals(), they must return the same
hashCode(). The reverse is not required —
unequal objects can still share a hash code (that is a
collision).
If you break this contract by overriding only
equals(), then putting such objects into a
HashMap or HashSet leads to
duplicate keys or lost lookups.
Q11 What are the four pillars of OOPs? +
Encapsulation, inheritance, polymorphism and abstraction.
- Encapsulation — bundling data and methods, hiding internals behind access modifiers.
- Inheritance — a subclass extends a superclass and inherits its members.
- Polymorphism — the same method name behaves differently depending on the object (compile-time via overloading, runtime via overriding).
- Abstraction — exposing only what the caller needs, hiding implementation detail behind interfaces or abstract classes.
Q12 What is the difference between method overloading and method overriding? +
Overloading is compile-time polymorphism — the same method name with different parameter lists, in the same class or across a hierarchy. Overriding is runtime polymorphism — a subclass provides its own implementation of a method it inherits.
| Feature | Overloading | Overriding |
|---|---|---|
| Binding | Compile time | Runtime |
| Parameter list | Must differ | Must be the same |
| Return type | Can differ | Same or covariant |
| Where | Same class or hierarchy | Subclass |
| Access modifier | No restriction | Cannot be more restrictive |
Q13 What is the difference between an abstract class and an interface? +
An abstract class can hold state (fields), constructors
and any mix of abstract and concrete methods. An
interface defines a contract — since Java 8 it can
also contain default and static
methods, and since Java 9 private helper methods.
| Feature | Abstract class | Interface |
|---|---|---|
| State (fields) | Yes | Only constants |
| Constructor | Yes | No |
| Multiple inheritance | No | Yes (implements many) |
| Access modifiers on methods | Any | Public (or private since Java 9) |
| When to use | Shared code + partial implementation | Pure contract, capability |
Q14 What is the difference between final, finally and finalize? +
final is a keyword that prevents change — a final variable cannot be reassigned, a final method cannot be overridden, a final class cannot be extended.
finally is a block that runs after a try-catch regardless of whether an exception was thrown. Used to release resources.
finalize() was a method the garbage collector called
before reclaiming an object. It is deprecated — use
try-with-resources or Cleaner instead.
Q15 What does the static keyword mean in Java? +
static means the member belongs to the class, not to any instance. A static variable is shared by all instances. A static method can be called without creating an object. A static block runs once when the class is first loaded.
class Counter {
static int count = 0;
Counter() { count++; }
}
public class Demo {
public static void main(String[] args) {
new Counter();
new Counter();
System.out.println(Counter.count); // 2
}
}
2
Q16 What are the access modifiers in Java? +
Java has four access levels, from most to least restrictive:
| Modifier | Same class | Same package | Subclass | Anywhere |
|---|---|---|---|---|
| private | Yes | No | No | No |
| default (no modifier) | Yes | Yes | No | No |
| protected | Yes | Yes | Yes | No |
| public | Yes | Yes | Yes | Yes |
Q17 What is constructor chaining in Java? +
Constructor chaining is calling one constructor from another,
either within the same class using this(...) or
from the superclass using super(...). It
removes duplication when several constructors share
initialisation logic.
class Student {
String name;
int age;
Student() {
this("Unknown", 0); // calls the 2-arg constructor
}
Student(String name, int age) {
this.name = name;
this.age = age;
}
}
this() or super() be the first
statement?" — Yes. The compiler inserts an implicit super() if you do
not write one.
Q18 What is the difference between checked and unchecked exceptions? +
Checked exceptions extend Exception but
not RuntimeException. The compiler forces you
to either catch them or declare them with
throws. Examples: IOException,
SQLException.
Unchecked exceptions extend
RuntimeException. They are usually programming
errors — NullPointerException,
ArrayIndexOutOfBoundsException,
IllegalArgumentException. The compiler does not
force you to handle them.
Throwable
├── Error
└── Exception
├── RuntimeException // unchecked
└── IOException, SQLException, ... // checked
Q19 What is try-with-resources in Java? +
try-with-resources automatically closes any resource that
implements AutoCloseable at the end of the
block, even if an exception is thrown. It replaces the old
finally { close(); } pattern and removes a
common source of bugs.
try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
System.out.println(br.readLine());
} catch (IOException e) {
e.printStackTrace();
} // br.close() is called automatically
Q20 What is the difference between ArrayList and LinkedList? +
ArrayList is backed by a resizable array — fast random access, slow inserts or deletions in the middle because elements must shift. LinkedList is a doubly-linked list — fast inserts and deletions at the ends, slow random access because it must walk the list.
| Operation | ArrayList | LinkedList |
|---|---|---|
| get(index) | O(1) | O(n) |
| add at end | O(1) amortised | O(1) |
| add/remove in middle | O(n) | O(n) to find, O(1) to link |
| Memory per element | Lower | Higher (two pointers) |
Intermediate Java interview questions
These questions come up in interviews for candidates with 2–5 years of experience. They test whether you understand the why behind Java's design, not just the syntax.
Q21 How does HashMap work internally in Java? +
A HashMap stores entries in an array of buckets.
When you put(key, value), Java computes
key.hashCode(), spreads the bits (XOR with
>>> 16), and maps the result to a
bucket index using (n - 1) & hash.
- If the bucket is empty, the entry is stored directly.
- If the bucket already has entries, they are compared with
equals(). Equal keys overwrite the value; unequal keys are stored in the same bucket. - When a bucket exceeds 8 entries and the table is at least 64 slots, the chain converts to a red-black tree, giving O(log n) lookup instead of O(n).
- When the map exceeds 75% of the array size (load factor 0.75), it doubles the array and rehashes all entries.
Q22 What is the difference between HashMap and Hashtable? +
HashMap is not thread-safe, allows one null key and
multiple null values, and is faster. Hashtable
(legacy, still present) is synchronized — every method is
synchronized — does not allow nulls, and is slower. For
new code, prefer ConcurrentHashMap over
Hashtable when you need thread safety.
Q23 What is ConcurrentHashMap and how is it different from HashMap? +
ConcurrentHashMap is a thread-safe map designed
for concurrent reads and writes. In modern Java it uses
per-bin locking with CAS operations rather than
locking the whole map, so reads are non-blocking and writes
only lock the affected bucket.
- No null keys or values (throws NPE).
- Reads scale well; writes have minimal contention.
- Preferred over
Collections.synchronizedMap()for high-traffic caches.
size() is an estimate under concurrent modification; use it for
monitoring, not for correctness.
Q24 What is the difference between HashMap, LinkedHashMap and TreeMap? +
All three implement Map, but they order keys
differently:
| Class | Order | get / put | When to use |
|---|---|---|---|
| HashMap | None | O(1) average | Default choice |
| LinkedHashMap | Insertion order | O(1) average | Predictable iteration, LRU caches |
| TreeMap | Sorted by key | O(log n) | Range queries, sorted reports |
Q25 What is the difference between fail-fast and fail-safe iterators? +
A fail-fast iterator throws
ConcurrentModificationException if the collection
is modified structurally while iterating. Iterators from
ArrayList, HashMap and
HashSet are fail-fast.
A fail-safe iterator iterates over a snapshot or a
concurrent view and does not throw. Iterators from
ConcurrentHashMap and
CopyOnWriteArrayList are fail-safe, but they
may not reflect updates made after iteration started.
Q26 What are generics in Java and why are they used? +
Generics let you write classes, interfaces and methods that
work on a type provided at use-time, with compile-time type
safety. Before generics, you had to cast and could get a
ClassCastException at runtime.
// Without generics — runtime risk
List list = new ArrayList();
list.add("hello");
Integer i = (Integer) list.get(0); // ClassCastException at runtime
// With generics — compile-time check
List<String> names = new ArrayList<>();
names.add("hello");
// names.add(1); // compile error — safer
List<String> and
List<Integer> are both just List. This is why you
cannot call new T().
Q27 What is a functional interface in Java? +
A functional interface has exactly one abstract
method. It can also contain any number of default and
static methods. The @FunctionalInterface
annotation tells the compiler to enforce this.
Common examples:
Runnable—void run()Callable<V>—V call()Comparator<T>—int compare(T, T)Function<T,R>,Predicate<T>,Supplier<T>,Consumer<T>— from java.util.function
Q28 What is a lambda expression in Java 8? +
A lambda is a compact way to implement a functional
interface. Instead of writing an anonymous class, you write
parameters, an arrow ->, and the body.
// Anonymous class
Runnable r1 = new Runnable() {
public void run() { System.out.println("run"); }
};
// Lambda
Runnable r2 = () -> System.out.println("run");
r2.run();
run
Q29 What is the Stream API in Java 8? +
The Stream API lets you process collections declaratively — filter, map, sort, reduce and collect — often in a single chained expression. Streams do not modify the source collection; they return new results.
List<String> names = List.of("Ravi", "Anita", "Sam", "Priya");
List<String> result = names.stream()
.filter(n -> n.length() > 3)
.map(String::toUpperCase)
.sorted()
.collect(Collectors.toList());
System.out.println(result);
[ANITA, PRIYA, RAVI]
Q30 What is the difference between intermediate and terminal operations in streams? +
Intermediate operations (filter, map, sorted, distinct, limit) return a new stream and are lazy — nothing runs until a terminal operation is called. Terminal operations (collect, forEach, reduce, count, anyMatch) end the stream and produce a result.
Q31 What is Optional in Java 8? +
Optional<T> is a container that may or may
not hold a value. It makes the possibility of absence
explicit in a method signature, replacing the habit of
returning null and hoping the caller checks.
Optional<String> name = Optional.ofNullable(findName());
System.out.println(name.orElse("Guest"));
System.out.println(name.map(String::toUpperCase).orElse("NONE"));
Q32 What are method references in Java 8? +
A method reference is shorthand for a lambda that only calls
an existing method. The syntax is
ClassName::methodName. There are four kinds:
- Static —
Integer::parseInt - Instance of a particular object —
System.out::println - Instance of an arbitrary object —
String::toUpperCase - Constructor —
ArrayList::new
Q33 What is the new Date and Time API in Java 8? +
The java.time package replaced the old
Date and Calendar classes. The
main types are:
LocalDate— a date without time or zone.LocalTime— a time without date or zone.LocalDateTime— date and time, no zone.ZonedDateTime— date and time with a time zone.Instant— a point on the timeline, used for timestamps.DurationandPeriod— amounts of time.
All of these are immutable and thread-safe, unlike the old classes.
Q34 What is the difference between a process and a thread? +
A process is an independent program with its own memory space. A thread is a lighter unit of execution inside a process — threads in the same process share the heap but have their own stack and program counter.
Because threads share memory, communicating between them is fast, but it also means you need synchronization to avoid race conditions.
Q35 What is the difference between Thread and Runnable? +
Thread is a class; Runnable is an
interface. Extending Thread uses your one
inheritance slot, so you cannot extend any other class.
Implementing Runnable keeps the class free to
extend something else and separates the task from the
thread that runs it.
Runnable task = () -> System.out.println("running");
Thread t = new Thread(task);
t.start();
running
Q36 What does the synchronized keyword do? +
synchronized ensures that only one thread at a
time can execute the marked block or method for a given
lock (usually the object instance or the class). It gives
both mutual exclusion and a memory barrier, so changes made
inside the block are visible to other threads that later
acquire the same lock.
For heavy concurrent workloads, prefer
java.util.concurrent classes such as
ReentrantLock,
AtomicInteger or
ConcurrentHashMap over manual
synchronized blocks.
Q37 What is the difference between synchronized and volatile? +
synchronized provides both mutual exclusion and visibility. volatile provides only visibility — it guarantees that reads and writes go straight to main memory and are seen by other threads, but it does not prevent multiple threads from interleaving.
Use volatile for a simple flag or a single
reference that is written by one thread and read by many.
Use synchronized when you need atomic
compound operations.
Q38 What is an ExecutorService in Java? +
ExecutorService is a higher-level replacement
for spawning threads manually. You submit tasks and it
manages a pool of worker threads, a queue, and lifecycle.
ExecutorService pool = Executors.newFixedThreadPool(3);
Future<Integer> f = pool.submit(() -> 2 + 3);
System.out.println(f.get()); // 5
pool.shutdown();
5
Q39 What is a deadlock and how do you avoid it? +
Deadlock happens when two or more threads wait on locks that each other hold, so none can proceed. It requires four conditions at once: mutual exclusion, hold-and-wait, no preemption, circular wait.
Practical ways to avoid deadlock:
- Always acquire locks in a fixed global order.
- Use
tryLock()with a timeout instead of blocking forever. - Keep lock scope small — do not call out to other services while holding a lock.
- Prefer concurrent collections and atomic classes over multiple manual locks.
Q40 What is serialization in Java? +
Serialization converts an object into a byte stream so it
can be saved to a file or sent over a network. The reverse
is deserialization. A class must implement
java.io.Serializable (a marker interface with
no methods).
- Use the
transientkeyword to skip a field (for example, a password). - Fields declared
staticare not serialized (they belong to the class, not the instance). - Declare a
private static final long serialVersionUIDto control version compatibility.
Java interview questions for experienced professionals
These questions come up for candidates with 5+ years of experience, or for anyone interviewing at a product company. They expect you to reason about trade-offs, not just recite definitions.
Q41 What is the Java memory model and what are the JVM memory areas? +
The Java Memory Model defines how threads interact through memory and what guarantees exist for visibility and ordering of operations.
The JVM divides memory into these areas:
- Heap — objects and their instance variables, shared across threads. Split into young generation (Eden + Survivor) and old generation.
- Stack — one per thread. Holds local variables, method call frames and partial results.
- Metaspace — class metadata (replaced PermGen from Java 8).
- PC Register — per-thread, holds the address of the current instruction.
- Native Method Stack — for native (non-Java) method calls.
Q42 How does garbage collection work in Java? +
Garbage collection frees heap memory occupied by objects that are no longer reachable from any live reference. Reachability is traced from GC roots — thread stacks, static fields, JNI references.
Common collectors in modern JVMs:
- G1 — the default from Java 9 onward. Divides the heap into regions and prioritises regions with the most garbage.
- ZGC and Shenandoah — low-pause collectors designed for very large heaps.
- Parallel — high-throughput; used historically for batch workloads.
You can tune heap size with -Xms and
-Xmx, and choose a collector with
-XX:+UseG1GC, -XX:+UseZGC and
similar flags.
Q43 What is the difference between a shallow copy and a deep copy? +
A shallow copy copies the object's fields, but reference fields still point to the same nested objects as the original. A deep copy recursively copies nested objects, so the copy is fully independent.
- Shallow copy:
Object.clone()by default, orArrays.copyOffor primitive arrays. - Deep copy: manual copy constructors, serialization round-trip, or third-party libraries such as ModelMapper.
Q44 What is the difference between Comparable and Comparator? +
Comparable defines the "natural ordering" of a class
via compareTo() — one sort order for the class.
Comparator is an external comparison strategy, so you
can define many orders without changing the class.
List<Employee> staff = new ArrayList<>();
// Natural order (Comparable) — by name
Collections.sort(staff);
// Custom order (Comparator) — by salary descending
staff.sort(Comparator.comparingDouble(Employee::getSalary).reversed());
Q45 What are records in Java and when should you use them? +
A record (Java 16, standard) is a compact declaration
for immutable data carriers. The compiler generates the
constructor, accessors, equals(),
hashCode() and toString().
public record Point(int x, int y) { }
Point p = new Point(3, 4);
System.out.println(p.x() + "," + p.y()); // 3,4
3,4
Use records for DTOs, API responses, value objects and small immutable groupings. Do not use them where you need mutable fields, inheritance or a lot of custom behaviour.
Q46 What is the var keyword in Java? +
var (Java 10) lets the compiler infer the type
of a local variable from its initialiser. It is
still statically typed — no dynamic typing is involved.
var list = new ArrayList<String>();
var count = 100;
// var x; // compile error — no initialiser
Use var when the right-hand side makes the type
obvious. Avoid it when the type is unclear, and never use it
for method parameters or return types.
Q47 What are sealed classes in Java? +
A sealed class or interface (Java 17, standard) can only be extended or implemented by a fixed, declared set of classes. This gives you controlled inheritance and better exhaustiveness checks with pattern matching.
public sealed interface Shape
permits Circle, Square { }
public record Circle(double radius) implements Shape { }
public record Square(double side) implements Shape { }
Q48 What is the difference between ClassNotFoundException and NoClassDefFoundError? +
ClassNotFoundException is a checked exception raised
at runtime when you explicitly try to load a class by name
(for example Class.forName()) and it is not on
the classpath. The application can catch and recover.
NoClassDefFoundError is a JVM error raised when the class was present at compile time but is missing or failed to initialise at runtime. It usually indicates a broken deployment or a failed static initialiser.
Q49 What is the difference between StringBuilder and String concatenation in a loop? +
In Java, a + b on strings is compiled to
StringBuilder.append() for that single
expression. Inside a loop, however, string concatenation
with += creates a new StringBuilder each
iteration and copies characters, so it becomes O(n²).
Using one StringBuilder across the loop is O(n).
String s = "";
for (int i = 0; i < 10000; i++) {
s += i; // creates a new builder each time
}
// Better
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) {
sb.append(i);
}
String result = sb.toString();
Q50 What is the difference between an inner class and a static nested class? +
An inner class (non-static nested) holds an implicit reference to the enclosing instance, so it can access its members directly. A static nested class does not hold that reference and behaves like a top-level class scoped inside another class.
Because the inner class keeps the enclosing instance alive, it can cause memory leaks if instances of the inner class outlive the outer. Prefer static nested classes unless you truly need access to the outer instance.
Q51 What is a memory leak in Java and how do you detect one? +
A Java memory leak happens when objects are no longer needed
but are still strongly reachable, so the garbage collector
cannot free them. Over time the heap fills, GC runs
constantly, and the JVM eventually throws
OutOfMemoryError.
Common causes:
- Static collections that keep growing.
- Listeners or callbacks registered but never removed.
- Long-lived caches without eviction.
- Inner class instances holding the outer reference.
Detect leaks with heap dumps and tools like Eclipse MAT, VisualVM or JProfiler. Look for the class with the most retained bytes and trace back to its GC root.
Q52 What is JDBC and how does it work? +
JDBC (Java Database Connectivity) is the standard API for connecting Java to relational databases. The main steps are:
- Load the driver (in modern JDBC 4+, this is automatic if the driver is on the classpath).
- Open a
Connectionusing a URL, username and password. - Create a
PreparedStatementand bind parameters (never concatenate strings — that invites SQL injection). - Execute and read the
ResultSet. - Close everything in a try-with-resources block, or use a connection pool such as HikariCP.
String sql = "SELECT id, name FROM users WHERE age > ?";
try (Connection conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, 18);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
System.out.println(rs.getInt("id") + " " + rs.getString("name"));
}
}
}
Q53 What is the difference between Statement, PreparedStatement and CallableStatement? +
Statement executes a plain SQL string — convenient but not safe for user input. PreparedStatement pre-compiles SQL and lets you bind parameters — safer and faster when executed many times. CallableStatement calls stored procedures and functions on the database.
Q54 What is the difference between a weak reference, soft reference and strong reference? +
Strong — the default. An object with a strong
reference is not collected until that reference goes away.
Soft — collected only when memory is low; useful for
caches. Weak — collected on the next GC cycle if
nothing else holds a strong reference; used by
WeakHashMap and listener registries.
Q55 How do you make a class immutable in Java? +
Five rules to make a class immutable:
- Declare the class
finalso it cannot be subclassed. - Make all fields
private final. - Do not provide setters.
- Initialise fields only in the constructor.
- For mutable fields (like a List or Date), return defensive copies on get, and copy incoming values on set.
Records give you most of this for free when fields are simple, but you still need defensive copies for mutable field types.
Scenario-based Java interview questions
These are the questions an interviewer asks when they want to see how you think under a realistic problem, not just how well you recall definitions. Answer with a step-by-step approach, not a single sentence.
S01 Your Java service is using 90% CPU in production. How do you debug it? +
Step 1 — Confirm it is CPU and not I/O wait. Check top or the container metrics for CPU vs load average.
Step 2 — Take a thread dump with jstack <pid> or
jcmd <pid> Thread.print. Look for threads in RUNNABLE state that
appear repeatedly.
Step 3 — If the same method shows up across many thread dumps, that is your hot path. Profile it with Java Flight Recorder or async-profiler to see whether it is your code, a library, or GC.
Step 4 — Check GC logs. High CPU can come from constant young-gen collections when allocation is high. The fix may be to reduce allocation, not to add CPUs.
Step 5 — Check for a retry storm or thread pool exhaustion calling downstream services. Bulkheads and timeouts often resolve a "high CPU" that is really a back-pressure problem.
S02 Your application is throwing OutOfMemoryError: Java heap space after running for hours. How do you approach it? +
Step 1 — Enable heap dumps on OOM with
-XX:+HeapDumpOnOutOfMemoryError and -XX:HeapDumpPath. The
next occurrence gives you evidence.
Step 2 — Open the dump in Eclipse MAT or VisualVM. Sort by retained size, then look at the dominator tree.
Step 3 — If the biggest consumer is a growing HashMap or
ArrayList held by a static field or a long-lived cache, you have a
leak. Either add eviction or clear the reference.
Step 4 — If no single object dominates, allocation is just too high. Reduce object creation, stream large results instead of loading them, and consider off-heap storage.
S03 Two threads are deadlocking in production. How do you find and fix it? +
Step 1 — Take a thread dump. The JVM often prints "Found one Java-level deadlock" and lists the threads with their waiting locks and held locks.
Step 2 — Identify the two locks and the order in which each thread acquired them. Deadlock almost always comes from inconsistent lock ordering.
Step 3 — Fix by enforcing a global lock order, or replace the two locks with a
single coarser lock, or use tryLock() with a timeout so one thread
backs off.
Step 4 — Add a test that spawns the same workload and asserts no deadlock in CI, so the fix does not regress.
S04 An API returns inconsistent data under load, but is correct when tested alone. What is going on? +
Step 1 — Suspect shared mutable state. Look for fields in a
@Service or @Controller that are not thread-safe — a
HashMap field, an unsynchronized counter, a shared
SimpleDateFormat.
Step 2 — Check whether the service is a singleton (the Spring default) and whether the field is truly read-only. If not, it must be a local variable or a thread-safe structure.
Step 3 — Look for missing transactions. Two threads reading and writing the same row without isolation can produce impossible numbers.
Step 4 — Reproduce with a load test (JMeter, Gatling or k6) and a fixed seed. Consistency bugs must be reproduced before they can be fixed confidently.
S05 Your Java service is spending a lot of time in garbage collection. How do you reduce it? +
Step 1 — Read the GC logs. You want the pause duration, frequency and how much is being collected.
Step 2 — If young-gen collections are frequent and short, the problem is allocation rate. Reduce object creation in hot paths — avoid unnecessary boxing, string concatenation and collection copies.
Step 3 — If full GCs are happening often, you may have a leak. Take a heap dump and investigate.
Step 4 — If the heap is large and pauses matter more than throughput, switch to a low-pause collector like ZGC or Shenandoah, and tune heap size and pause goals.
S06 A method takes 20 seconds when it should take 200 ms. How do you profile it? +
Step 1 — Add timing logs around the top-level call and around each sub-step. Find which step accounts for the 20 seconds. Do not guess — measure.
Step 2 — If the slow step is a database query, run it directly with EXPLAIN and check indexes, row counts and whether N+1 queries have crept in.
Step 3 — If the slow step is a remote call, check the timeout, retry policy and whether it is inside a loop. Batching, caching and parallelising independent calls are common fixes.
Step 4 — If the slow step is CPU-bound Java code, attach a profiler. Look for repeated work that can be hoisted out of loops, unnecessary sorting, or string building inside a loop.
S07 A query is correct in development but times out in production on the same data volume. Why? +
Step 1 — Check statistics and indexes. Developers often have more indexes locally, or fresher statistics, than production.
Step 2 — Check the query plan in both environments. The same SQL can produce different plans on different data distributions.
Step 3 — Check for competing load. The query may be fine in isolation but starved by other long-running queries or lock contention.
Step 4 — Check bind variable types and implicit conversions. A
varchar column compared to a number can disable an index and scan the
whole table.
S08 You need to process a large list in parallel and preserve order in the result. What do you use? +
Use a parallel stream when you can live with the default
ForkJoinPool and the task is CPU-bound — the results of
map preserve order when collected with
toList().
For I/O-bound work, do not use parallel streams. Use an
ExecutorService and submit tasks in order,
collect the Future objects in a list, and call
get() in the original order. That preserves
order while still running the work in parallel.
ExecutorService pool = Executors.newFixedThreadPool(8);
List<Future<String>> futures = new ArrayList<>();
for (String input : inputs) {
futures.add(pool.submit(() -> process(input)));
}
List<String> ordered = new ArrayList<>();
for (Future<String> f : futures) ordered.add(f.get());
pool.shutdown();
Java coding round — programs with code and output
These are the twelve programs that come up most often in Java coding rounds in India. Write each one by hand at least once before your interview — reading code is not the same as writing it. Every snippet below is complete and runnable on Java 8 or later.
C01 Reverse a string without using StringBuilder.reverse() +
public class ReverseString {
public static void main(String[] args) {
String input = "Uncodemy";
char[] chars = input.toCharArray();
int left = 0, right = chars.length - 1;
while (left < right) {
char temp = chars[left];
chars[left] = chars[right];
chars[right] = temp;
left++;
right--;
}
System.out.println(new String(chars));
}
}
ymedocnU
C02 Check whether a string is a palindrome +
public class Palindrome {
public static void main(String[] args) {
String s = "madam";
int i = 0, j = s.length() - 1;
boolean isPalindrome = true;
while (i < j) {
if (s.charAt(i) != s.charAt(j)) { isPalindrome = false; break; }
i++; j--;
}
System.out.println(isPalindrome);
}
}
true
C03 Swap two numbers without using a third variable +
public class Swap {
public static void main(String[] args) {
int a = 5, b = 9;
a = a + b; // a = 14
b = a - b; // b = 5
a = a - b; // a = 9
System.out.println("a=" + a + " b=" + b);
}
}
a=9 b=5
C04 Print the Fibonacci series up to N terms +
public class Fibonacci {
public static void main(String[] args) {
int n = 8, a = 0, b = 1;
for (int i = 0; i < n; i++) {
System.out.print(a + " ");
int next = a + b;
a = b;
b = next;
}
}
}
0 1 1 2 3 5 8 13
C05 Check whether a number is prime +
public class PrimeCheck {
static boolean isPrime(int n) {
if (n < 2) return false;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) return false;
}
return true;
}
public static void main(String[] args) {
System.out.println(isPrime(29));
System.out.println(isPrime(30));
}
}
true false
C06 Factorial using recursion +
public class Factorial {
static long fact(int n) {
if (n <= 1) return 1;
return n * fact(n - 1);
}
public static void main(String[] args) {
System.out.println(fact(6));
}
}
720
C07 Find duplicate characters in a string using HashMap +
import java.util.*;
public class DuplicateChars {
public static void main(String[] args) {
String s = "programming";
Map<Character, Integer> map = new HashMap<>();
for (char c : s.toCharArray()) {
map.put(c, map.getOrDefault(c, 0) + 1);
}
for (Map.Entry<Character, Integer> e : map.entrySet()) {
if (e.getValue() > 1) {
System.out.println(e.getKey() + " = " + e.getValue());
}
}
}
}
r = 2 g = 2 m = 2
C08 Find the second highest number in an array +
public class SecondHighest {
public static void main(String[] args) {
int[] arr = { 12, 45, 7, 92, 63, 92, 28 };
int first = Integer.MIN_VALUE, second = Integer.MIN_VALUE;
for (int n : arr) {
if (n > first) { second = first; first = n; }
else if (n > second && n != first) { second = n; }
}
System.out.println(second);
}
}
63
C09 Sort a list of objects with Comparator +
import java.util.*;
class Employee {
String name;
double salary;
Employee(String n, double s) { name = n; salary = s; }
public String toString() { return name + " " + salary; }
}
public class SortObjects {
public static void main(String[] args) {
List<Employee> list = new ArrayList<>();
list.add(new Employee("Ravi", 55000));
list.add(new Employee("Anita", 72000));
list.add(new Employee("Sam", 48000));
list.sort(Comparator.comparingDouble(e -> e.salary).reversed());
list.forEach(System.out::println);
}
}
Anita 72000.0 Ravi 55000.0 Sam 48000.0
C10 Stream examples — filter, map, collect and groupingBy +
import java.util.*;
import java.util.stream.*;
public class StreamDemo {
public static void main(String[] args) {
List<String> names = List.of("Ravi", "Anita", "Sam", "Priya", "Arjun");
List<String> upper = names.stream()
.filter(n -> n.length() > 3)
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(upper);
Map<Integer, List<String>> byLength = names.stream()
.collect(Collectors.groupingBy(String::length));
System.out.println(byLength);
}
}
[ANITA, PRIYA, ARJUN]
{3=[Sam], 4=[Ravi], 5=[Anita, Priya, Arjun]}
C11 Create and use a custom exception +
class InsufficientBalanceException extends Exception {
InsufficientBalanceException(String msg) { super(msg); }
}
class Account {
double balance = 5000;
void withdraw(double amt) throws InsufficientBalanceException {
if (amt > balance) throw new InsufficientBalanceException("Balance too low for " + amt);
balance -= amt;
}
}
public class CustomExceptionDemo {
public static void main(String[] args) {
Account acc = new Account();
try {
acc.withdraw(9000);
} catch (InsufficientBalanceException e) {
System.out.println("Caught: " + e.getMessage());
}
}
}
Caught: Balance too low for 9000.0
C12 Implement a thread-safe singleton in Java +
The cleanest thread-safe singleton is an enum — the JVM guarantees a single instance and it is safe against reflection and serialization attacks.
public enum AppConfig {
INSTANCE;
private final Map<String, String> settings = new HashMap<>();
public void put(String k, String v) { settings.put(k, v); }
public String get(String k) { return settings.get(k); }
}
If you must use a class (for inheritance reasons), use the holder pattern — lazy, thread-safe and no synchronization cost:
public class AppConfig {
private AppConfig() { }
private static class Holder {
private static final AppConfig INSTANCE = new AppConfig();
}
public static AppConfig getInstance() { return Holder.INSTANCE; }
}
Spring Boot basics for Java developers
Most Java developer roles in India also expect basic Spring Boot knowledge. These eight questions cover what comes up in almost every entry-level and mid-level Java interview.
B01 What is Inversion of Control (IoC) and Dependency Injection (DI)? +
IoC means the framework, not your code, controls object creation and lifecycle. DI is how IoC is implemented — the framework supplies the dependencies a class needs, instead of the class constructing them itself.
This reduces coupling: your service depends on an interface, and Spring injects whichever implementation is configured.
B02 What does the @SpringBootApplication annotation do? +
It is a convenience annotation that combines three others:
@Configuration— the class can define beans.@EnableAutoConfiguration— Spring Boot auto-configures beans based on the dependencies on the classpath.@ComponentScan— scans the package of the annotated class and its sub-packages for components.
B03 What is the difference between @Component, @Service, @Repository and @Controller? +
All four register a class as a Spring bean. The difference is semantic — they help the reader understand the role of each class, and in two cases they add behaviour.
| Annotation | Layer | Special behaviour |
|---|---|---|
| @Component | Generic | None |
| @Service | Business logic | None — alias for @Component |
| @Repository | Data access | Translates database exceptions to Spring's DataAccessException |
| @Controller / @RestController | Web layer | Handles HTTP requests; @RestController adds @ResponseBody |
B04 What is the difference between @Autowired and constructor injection? +
@Autowired can be applied to a field,
setter or constructor. Field injection is simple but makes
testing harder and hides the real dependencies of a class.
Constructor injection makes dependencies explicit, allows
final fields, and makes the class trivially testable
without a Spring context. Modern Spring code prefers
constructor injection. If there is only one constructor,
@Autowired is optional on it.
B05 What is @RestController and how is it different from @Controller? +
@Controller marks a class as a web controller
and typically returns a view name. @RestController
is @Controller plus @ResponseBody
— the return value of each method is serialized directly as
the HTTP response body (usually JSON via Jackson).
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserService service;
public UserController(UserService service) { this.service = service; }
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return service.findById(id);
}
}
B06 What are Spring profiles and how are they used? +
Profiles let you define different bean configurations and
properties for different environments — dev, test,
staging, prod. You activate a profile with
spring.profiles.active=dev in
application.properties, as a command-line
argument, or as an environment variable.
@Configuration
@Profile("dev")
public class DevDataSourceConfig { /* in-memory DB */ }
@Configuration
@Profile("prod")
public class ProdDataSourceConfig { /* real DB */ }
B07 How do you create a simple REST endpoint in Spring Boot? +
Annotate the class with @RestController and
map methods with @GetMapping,
@PostMapping and so on. Path variables come
from @PathVariable, query parameters from
@RequestParam, and request bodies from
@RequestBody.
@RestController
@RequestMapping("/api/products")
public class ProductController {
@GetMapping
public List<Product> list(@RequestParam(defaultValue = "0") int page) {
return productService.findAll(page);
}
@PostMapping
public Product create(@RequestBody Product product) {
return productService.save(product);
}
}
B08 How do you handle exceptions globally in Spring Boot? +
Use @ControllerAdvice with
@ExceptionHandler methods. The handler runs
whenever the mapped exception is thrown anywhere in your
controllers, so you keep error handling out of individual
endpoints.
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse(ex.getMessage()));
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAll(Exception ex) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("Unexpected error"));
}
}
Quick-revision cheat table
Fifteen one-line definitions and syntax reminders to skim on the morning of your interview.
| Topic | One-line reminder |
|---|---|
| JDK vs JRE vs JVM | JDK = compiler + JRE, JRE = JVM + libraries, JVM = runs bytecode. |
| == vs equals() | == compares references, equals() compares content. |
| equals & hashCode | Equal objects must return equal hash codes. |
| String immutability | final class, final char array, no setters — pool + thread safety. |
| StringBuilder vs StringBuffer | Same API, StringBuilder is faster, StringBuffer is synchronized. |
| Overloading vs overriding | Overloading = same name, different params, compile time; overriding = same signature, runtime. |
| Abstract class vs interface | Abstract = partial implementation + state; interface = contract (+default/static since Java 8). |
| final / finally / finalize | final = constant, finally = runs always, finalize = deprecated. |
| Checked vs unchecked | Checked extends Exception, unchecked extends RuntimeException. |
| ArrayList vs LinkedList | ArrayList = O(1) get, LinkedList = O(1) insert at ends. |
| HashMap internals | Array of buckets, hashCode → index, treeify at 8, resize at 0.75 load. |
| HashMap vs ConcurrentHashMap | HashMap = not thread-safe, CHM = per-bin locks, no nulls. |
| Functional interface | Exactly one abstract method — Runnable, Comparator, Function, Predicate. |
| Stream intermediate vs terminal | Intermediate is lazy and returns a stream; terminal ends the stream and produces a result. |
| synchronized vs volatile | synchronized = mutual exclusion + visibility; volatile = visibility only. |
How to prepare for a Java interview in 7 days
If your interview is next week, follow this plan. Each day has a single focus and a practice task — do not just read, write code.
| Day | Focus | Practice task |
|---|---|---|
| Day 1 | Language fundamentals | Answer Q1–Q10 of the beginner level out loud. Write three small programs that use autoboxing, == vs equals, and String immutability. |
| Day 2 | OOPs and design | Answer Q11–Q20. Write one example each of overloading, overriding, abstract class vs interface and an immutable class. |
| Day 3 | Collections and generics | Write the HashMap internal walkthrough from scratch, then code a custom Comparator and a sort using streams. |
| Day 4 | Java 8 and modern Java | Solve five stream problems (filter, map, collect, groupingBy, reduce). Practice records, var and switch expressions. |
| Day 5 | Multithreading and JVM | Write a program with ExecutorService and Futures. Answer Q37, Q38, Q39 from memory. Read the memory model question again. |
| Day 6 | Coding round | Write all 12 coding programs by hand, without looking at the code. Then time yourself on the two hardest ones. |
| Day 7 | Spring Boot and mock | Answer the 8 Spring Boot questions. Do a mock interview — answer one question per level out loud, recording yourself if possible. |
Common mistakes candidates make
Memorising without understanding
Reciting "HashMap has an array of buckets" is not enough — you must be able to walk through what happens on put, get, resize and treeify.
Reading code instead of writing it
You will not remember how to reverse a string by reading it three times. Write it once by hand, then again without looking.
Guessing when you do not know
If you do not know an answer, say "I am not sure, but my understanding is…" and reason aloud. Interviewers respect honest reasoning more than confident nonsense.
Skipping the coding round
Many candidates prepare only Q&A and then freeze when asked to write code. Practise writing on paper or a plain editor — no IDE autocomplete.
Ignoring multithreading
Even fresher interviews now ask about threads, synchronized and deadlock at least at a definition level. Do not skip the topic.
Not asking clarifying questions
In scenario questions, ask about scale, constraints and expected behaviour before answering. Interviewers notice whether you clarify before you code.
Practise these topics with Uncodemy
If you want structured, live practice on these topics rather than self-study, Uncodemy runs Java and Java Full Stack programs that cover the same ground as this page. The batch is taught live, and you can attend two classes before deciding.
| Program | What it covers for interviews | Duration |
|---|---|---|
| Java Training | Core Java, OOPs, collections, exceptions, Java 8 features — the foundation for the beginner and intermediate rounds on this page. | See the course page or ask a counsellor for the current fee and batch. |
| Java Expert | Advanced Java, multithreading, collections internals, JVM basics — matches the experienced-level questions. | See the course page or ask a counsellor for the current fee and batch. |
| Java Full Stack using React | Java backend plus Spring Boot, REST APIs and React frontend — covers the Spring Boot section here as well. | See the course page or ask a counsellor for the current fee and batch. |
Placement assistance (as published by Uncodemy): resume building, LinkedIn optimisation, portfolio review, interview preparation, mock interviews and opportunity sharing through the placement network. Uncodemy does not guarantee employment, as hiring decisions rest with employers. See placement support.
Also useful: AI career guidance for picking a path, and the 2-class free trial to see how a live batch runs before you commit.
Java interview preparation FAQs
F1 How do I prepare for a Java interview as a fresher? +
F2 Which Java version should I learn for interviews? +
F3 Is DSA asked in Java developer interviews? +
F4 Should I learn Spring Boot before applying for Java jobs? +
@SpringBootApplication works,
@RestController and @Autowired,
profiles, and exception handling with
@ControllerAdvice — all covered in the Spring
Boot section above.