128 Java interview questions with detailed answers, sorted from basic to advanced. Free to practice, with progress saved automatically.
Java is an object-oriented language compiled to bytecode that runs on the JVM, commonly used for enterprise backend applications. Questions cover the roles of the JVM, JRE, and JDK, OOP and design, the Collections Framework and HashMap internals, generics, the Stream API, threads, thread pools and locking, and JVM memory management.
and 28 more topics.
Java is a statically typed, object-oriented language released in 1995. javac compiles Java code into bytecode (.class files) that the JVM then runs, so any machine with a JVM runs the same .class file without recompiling. Why it is still widely used: - Good performance…
== asks "is this the same object?", while .equals() asks "is the content equal?". == .equals() --------- What it is A language operator, cannot be overridden A method on Object, classes override it On primitives (int, boolean…) Compares values Not applicable On objects Compares references:…
No. A purely object-oriented language is one where every value is an object, like Smalltalk: even the number 5 is an object with methods. Java has 8 primitive types (int, long, double, boolean, char, byte, short, float) that are not objects, so Java is not…
The stack is a per-thread memory area that holds the frames of running methods: each frame keeps local variables and parameters. The heap is shared by the whole JVM, holds every object created with new, and is cleaned by the Garbage Collector. When demo() is…
The five usually listed are: object-oriented, platform-independent, automatic memory management, built-in multithreading, and runtime safety. Most of them come from the fact that Java does not compile straight to machine code but to bytecode, which the JVM (Java Virtual Machine) then runs. Hello.class is not…
String is immutable = once created, its content cannot change; every operation like concat(), replace() returns a new object instead of modifying the existing one. Design reasons: - The String pool depends on it: the JVM maintains a cache where multiple variables can point to…
String cannot be changed after creation (immutable); StringBuilder and StringBuffer can be changed in place (mutable). The latter two differ only in that StringBuffer is synchronized so several threads can share it. String StringBuilder StringBuffer ------------ Modify in place No, every "change" creates a new…
Constructor overloading is when a class has multiple constructors with the same name as the class but different parameter lists (type, count, or order). When you call new, the compiler picks the constructor that matches the arguments passed. It works like method overloading: Java uses…
Access modifiers are keywords that control the visibility of a class, field, method, or nested class in Java. There are four levels, from most restrictive to least: private, default (no modifier), protected, public. The table below summarizes access levels: Modifier Same class Same package Subclass…
Easy to confuse because both start with "over", but they solve different problems. Overloading Overriding --------- Scope Same class, or between a parent and a child class Subclass redefines the parent's method Signature Different parameters (count or types) Same signature as the parent Resolution Compile-time…
The four principles of OOP are Encapsulation, Inheritance, Polymorphism and Abstraction. One small example shows all four: - Abstraction: Shape only declares "every shape can compute its area", not how. - Encapsulation: radius is private, so only Circle can read it. So changing how the…
Static members belong to the class, not to individual instances. Picture it this way: private int balance is each account's own balance; static int totalAccounts is a single variable shared by every Account. Each new Counter() increments both total and instanceCount by 1. After creating…
A NullPointerException (NPE) is thrown when you invoke a method, access a field, or unbox a primitive on a reference that is null. Tony Hoare called inventing null his "billion-dollar mistake". In the second example, m.get("b") returns null because key "b" is absent. Assigning it…
- this is a reference to the current object ("myself"). - super is how you reach the parent class's part that the subclass has overridden or hidden. new Dog("Rex", "Lab").describe() prints Animal: Rex and then Breed: Lab. Thanks to super.describe(), Dog reuses Animal's printing instead…
Three contexts, one idea: "cannot change", but what cannot change depends on the context: - final class: nobody can extend it (for example String, Integer), so the class's behavior cannot be changed by a subclass. String is final so that it stays immutable; if it…
Abstract class Interface --------- Inheritance extends only one implements many Constructor Yes No State (instance fields) Yes No — (constants only) Concrete default methods Yes Yes — (Java 8+) Semantics "is-a" "can-do" (capability) When to pick which: - Abstract class: subclasses form one family +…
The Collections Framework is a unified architecture in Java for storing and manipulating groups of objects, providing shared interfaces, implementations, and utilities. It has existed since JDK 1.2 and underpins most data handling in Java. The main interface hierarchy: The framework has three layers: -…
ArrayList is a dynamic array, LinkedList is a doubly-linked list. The core difference is the internal structure: ArrayList stores elements contiguously in an array, while LinkedList stores each element in a separate node with pointers to the previous and next nodes. Think of ArrayList as…
HashSet TreeSet --------- Structure Hash table Red-black tree add/contains O(1) average O(log n) Iteration order Unspecified Sorted Null 1 null element No — (NPE) Requirements Correct hashCode() + equals() Comparable or Comparator Extra API — first, last, subSet, floor, ceiling When to use: - HashSet:…
Both are Maps that store key-value pairs. They differ in internal structure, and that structure decides both speed and key order. HashMap TreeMap --------- Structure Hash table (since Java 8, a bucket with many entries turns into a red-black tree) Red-black tree get/put O(1) average…
Different purpose, same internals. HashSet<E HashMap<K,V --------- Implements Set Map Stores Unique elements Key → value pairs Methods add, contains, remove put, get, remove Truth: HashSet is really a wrapper around HashMap — the value is a shared dummy object: Which to use: - "Is…
Iterator<E is the interface for walking through a collection without knowing whether it is an array, a linked list or a tree inside. It has two main methods: hasNext() asks whether any element is left, and next() returns the next one. The most important reason…
Three modes for handling "collection modified during iteration": Fail-fast Fail-safe (snapshot) Weakly-consistent ------------ Examples ArrayList, HashMap CopyOnWriteArrayList ConcurrentHashMap Behavior Throws ConcurrentModificationException Iterates a copy, no throw, does not see new changes No throw, may or may not see new changes Cost Almost none (just compares…
Comparable<T Comparator<T --------- Lives Inside class T Outside, separate class/lambda Method int compareTo(T o) int compare(T a, T b) orderings One (natural) Many strategies Return value: negative = this first, 0 = equal, positive = this later. Note: - Do not use a - b…
Queue<E is a FIFO (First-In-First-Out) collection — the element that went in first comes out first, like a line of people. The API has two flavours: Operation Throws exception Returns special value --------- Insert add(e) offer(e) → false if full Remove remove() → NoSuchElementException poll()…
Both are thread-safe and differ in locking scope: Hashtable locks the whole map, ConcurrentHashMap locks only the small part being written. Hashtable (legacy) ConcurrentHashMap (Java 5+) --------- Locking synchronized on every method: only one thread at a time may enter the map Bucket-level lock +…
In theory there are 5 kinds of inheritance. With classes, Java supports 3; the other two need multiple inheritance (a class with several parent classes), which Java forbids, and can only be simulated through interfaces. 1. Single: A → B. 2. Multilevel: A → B…
LSP (the "L" in SOLID, Barbara Liskov 1987): a subtype must be substitutable for its supertype without breaking program behavior. Code written for Animal must still work correctly when given a Dog — no surprises. Classic violation — Square is-a Rectangle: Mathematically a square is…
Polymorphism ("many forms") — the same interface behaves in many ways. Java has two kinds: 1. Compile-time — Method overloading: same name, different signatures → compiler picks at compile time. 2. Runtime — Method overriding: the subclass has its own version → the JVM dispatches…
An abstract class cannot be instantiated directly — it serves as a template for subclasses. Subclasses must implement abstract methods. Traits: has constructors, has state (instance fields), mixes abstract + concrete methods, all access modifiers available. Only one parent. When to pick an abstract class…
An interface defines a contract — a list of methods implementations must provide. It separates "what can be done" from "how". A class can implements many interfaces. Evolution timeline: Version Added ------ Java ≤ 7 Only public abstract methods + public static final constants Java…
SOLID is 5 OOP design principles (Robert C. Martin): S Single Responsibility, O Open/Closed, L Liskov Substitution, I Interface Segregation, D Dependency Inversion. S — Single Responsibility: A class should have only one reason to change. Not "1 class = 1 method" but "1 class…
Singleton restricts a class to exactly one instance with a global access point. Common for: loggers, config, DB pools, caches. Implementations, simple → best: 1. Eager — simple, thread-safe via JVM. Downside: created even when unused. 2. Bill Pugh — initialization-on-demand holder (recommended): Truly lazy…
Factory separates "creating objects" from "using objects". Callers do not call new ConcreteClass(); they ask a factory which decides what to return. Why use it: swap implementations, hide complexity, caching/pooling, easier testing. Three main variants: 1. Simple Factory: 2. Factory Method (GoF): subclasses decide the…
Inheritance ("is-a") Composition ("has-a") --------- Mechanism class B extends A class B { A a; } Coupling Tight — knows parent internals Loose — depends on the interface Change at runtime No Yes (swap the member) Effective Java principle: favor composition over inheritance. Classic example…
Method hiding happens when a subclass declares a static method with the parent's signature → not overriding, but hiding. The JVM dispatches by reference type (compile-time). Hiding Overriding --------- Applies to static methods Instance methods Dispatch By reference type By object type (vtable) @Override No…
A thread is a path of execution: it lets several pieces of code run at the same time inside one program. Every Java app already has a main thread; you create more threads so slow work (API calls, file reads) does not block main. There…
Synchronization ensures only one thread runs inside a critical section at a time, which prevents race conditions when several threads share data. The synchronized keyword uses an object's intrinsic lock: Why sync count++? It is three steps: read, add, write. If two threads interleave between…
Deadlock occurs when multiple threads wait for each other's locks in a circular way — all blocked forever. The app does not crash; it just "freezes". Four Coffman conditions (all must hold): mutual exclusion, hold-and-wait, no preemption, circular wait. Breaking circular wait is the most…
ExecutorService (Java 5+) manages a thread pool — you submit Runnable/Callable, the executor handles the rest. If every request creates a new Thread(), 10,000 simultaneous requests produce 10,000 OS threads and can end in OutOfMemoryError. Threads are not reused and nothing limits how much work…
volatile guarantees visibility across threads: a write to a volatile variable in one thread is seen by every later read in another thread. The JVM achieves this by inserting memory barriers per the Java Memory Model, which forbid the compiler/CPU from reordering instructions around that…
Future (Java 5) represents an async result. Limitations: get() blocks, no chaining, awkward exception handling. CompletableFuture (Java 8+) addresses this: non-blocking, chainable, clean exception handling. Common operators: thenApply (map), thenCompose (flatMap), thenAccept (consumer), thenCombine (zip two CFs), handle (success + error). Structured concurrency: StructuredTaskScope is…
Race condition occurs when multiple threads access shared data concurrently and the final result depends on execution order → unpredictable. Prevention, in order of preference: 1. Atomic variables: AtomicInteger.incrementAndGet() — lock-free, CAS. 2. synchronized / Lock for multi-step critical sections. 3. Immutable objects — no…
- JVM (Java Virtual Machine): executes bytecode, platform-specific (each OS has its own JVM), provides runtime + GC + JIT. - JRE (Java Runtime Environment): JVM + standard libraries. Runs compiled Java programs, cannot compile. - JDK (Java Development Kit): JRE + compiler javac +…
GC automatically reclaims memory from objects that are no longer referenced, so Java developers do not call free() by hand. Three core steps: 1. Marking — traverse the object graph from GC roots (stack frames, static fields, JNI refs) and mark reachable objects. 2. Sweeping…
The heap is split into two regions based on object age: Rationale (weak generational hypothesis): most objects die young — created and discarded quickly (e.g. local variables in a method). Process: 1. New objects go to Eden. 2. Minor GC runs frequently in Young Gen…
OutOfMemoryError (OOM) is thrown when the JVM cannot allocate memory — heap exhausted, GC cannot free enough. Common OOM variants: - Java heap space — heap full. Most common. - GC overhead limit exceeded — GC runs 98% of the time but frees <2%. -…
Java memory leak: an object is still referenced but no longer needed — GC cannot collect it (GC only reclaims unreachable objects). Common causes: - Unclosed resources: file handles, DB connections, network sockets. - Unregistered listeners: the subject still holds a reference. - Unbounded static…
Stack overflow Heap overflow --------- Memory area Stack (per-thread, about 1MB by default on Linux x64) Heap (shared, GB) Cause Too-deep recursion, nested method calls Too many objects / memory leak Exception StackOverflowError OutOfMemoryError: Java heap space Detection Fast, clear (deep stack trace) Slow, GC…
A ClassLoader loads .class files into memory at runtime. Three built-in types (by hierarchy): 1. Bootstrap ClassLoader — JVM built-in (written in C++), loads core classes such as java.lang, java.util. Before Java 9 they lived in rt.jar; since Java 9 they belong to core modules…
Virtual Threads (Project Loom, Java 21 GA) are lightweight threads managed by the JVM — run millions on just a few OS threads. The pre-Java 21 problem: Platform Threads are 1:1 with OS threads; each keeps its own stack (about 1MB of virtual memory by…
Records (Java 16+ — JEP 395) are a special class for immutable data carriers. One line replaces 50 lines of POJO. The compiler generates: canonical constructor, accessors name() / age() (no get prefix), equals / hashCode / toString, fields implicitly private final. Customise via compact…
A sealed class (Java 17+, JEP 409) declares exactly which classes may extends it, through permits. Every subclass must be final, sealed or non-sealed. Interfaces can be sealed too. The most common use is together with pattern matching for switch (final in Java 21). Because…
A text block (Java 15, JEP 378) is a multi-line string wrapped in """. It lets you write JSON, SQL or HTML without joining lines with + and escaping \n and \" by hand. The result is still a regular String, not a new type.…
Pattern matching for switch (Java 21 — JEP 441) lets switch test by type, bind a properly-cast variable, and add a when guard — collapsing long if-instanceof chains. The example above assumes Shape is a sealed interface that permits only Circle, Square and Triangle. That…
Java mandates: 1. If a.equals(b) == true → a.hashCode() == b.hashCode() required. 2. The reverse is not required — two different objects may share a hashCode (hash collision). Why both must be overridden: HashMap/HashSet first finds the bucket via hashCode(), then uses equals() to locate…
Comparable is an interface a class implements itself to define its own natural ordering (exactly one). A Comparator is a comparison object that lives outside the class, so you can create as many sort orders as you like without touching the class. Comparable Comparator ---------…
Three keywords that are completely unrelated despite similar names — this question tests how solid your fundamentals are. - final — a modifier: variables cannot be reassigned, methods cannot be overridden, classes cannot be extended (see the final keyword item). - finally — a block…
wait() sleep() --------- Belongs to Object (instance method) Thread (static method) Monitor lock Releases the lock while waiting Keeps the lock Wakes up on notify()/notifyAll() or timeout Time elapsed Call requirement Must be inside synchronized (else IllegalMonitorStateException) Anywhere Used for Thread coordination (producer–consumer) Pausing the…
Java is always pass-by-value — there is no pass-by-reference. The confusing part: for objects, what gets copied is the value of the reference (the address pointing to the object), not the object itself. Consequences: - A method can mutate the state of the caller's object…
Core structure: a bucket array; entries land in a bucket via hash(key) & (n - 1) (n = capacity, always a power of 2). put(key, value): 1. Compute the hash from the key's hashCode() (the JDK mixes in high bits to reduce collisions). 2. Locate…
The String pool (string constant pool) is a cache area in the heap holding String literals — identical literals share one object. - String a = "hello" → the JVM checks the pool: if present, returns the existing reference → "hello" == "hello" is true…
An immutable class = an object whose state never changes after creation. The rules: 1. Declare the class final — prevents subclasses from overriding methods to expose/alter state. 2. Every field private final. 3. No setters — state is assigned once via the constructor. 4.…
Shallow copy Deep copy --------- What is copied The outer object; inner object fields share references The entire object graph, recursively Consequence Mutating a child object → both copies see it Two fully independent copies Cost Cheap More expensive (walks the graph) Object.clone() is shallow…
The JIT (Just-In-Time) compiler compiles bytecode → native machine code at runtime instead of interpreting instruction by instruction. The JVM starts in interpreter mode (runs immediately, no warm-up) while counting how often each method/loop runs. Once a threshold ("hot") is crossed, the JIT compiles and…
Wrapper classes are the object form of primitives: int→Integer, double→Double, boolean→Boolean... You need them because Collections/Generics only accept objects (List<Integer, never List<int). - Autoboxing: the compiler inserts Integer.valueOf(x) when a primitive is assigned where an object is expected. - Unboxing: it inserts i.intValue() the other…
Both shift bits right; they differ in what fills in on the left: - (signed / arithmetic): fills with the sign bit → negatives stay negative. - (unsigned / logical): always fills 0 → the result is never negative. For positive numbers the two operators…
Covariant return = when overriding a method, the subclass may return a subtype of the type the parent declared, rather than the exact same type. Added in Java 5. Before Java 5 you had to return exactly Animal, forcing callers to cast (Cat). Covariant returns…
transient marks a field as excluded from serialization. When an object is written to bytes by ObjectOutputStream, transient fields are skipped; on deserialization they get their default value (0, false, null). Use it when a field is: (1) sensitive (password, token) and should not sit…
A marker interface is an empty interface (no methods) — used only to tag a class, signalling to the JVM/libraries that the class has some property. Canonical examples: Serializable, Cloneable, RandomAccess. Mechanism: other code checks via instanceof. ObjectOutputStream hitting a non-Serializable object throws NotSerializableException; Object.clone()…
Make a constructor private to forbid outside new and take back control over how objects are created. Common cases: - Utility class with only static members (like Math, Collections): a private constructor stops anyone accidentally calling new. - Singleton: a single instance obtained via getInstance().…
ArrayList wraps an Object[] array. When you add and the array is full, it allocates a larger array and copies all elements over. - The default is initialized empty; the first add allocates capacity 10. - When full, the new capacity is ≈ old ×…
Because autoboxing does not call new Integer(...); it calls Integer.valueOf(int), which returns a cached instance for small values. - JLS 5.1.7 mandates caching for boolean, byte, char in \u0000–\u007f, and short/int in -128..127. Within that range two boxing conversions of the same value must yield…
You get a ConcurrentModificationException. Iterators in java.util are fail-fast: they capture modCount at creation and re-check it on every next(); calling list.remove(...) directly desynchronizes that counter and throws immediately. Three correct approaches: Secondary trap: removing the second-to-last element in a for-each does not throw —…
Arrays.asList() returns a fixed-size view (java.util.Arrays$ArrayList, not java.util.ArrayList) backed by the original array. There is nowhere to put extra elements, so add/remove/clear throw UnsupportedOperationException. Versus List.of() (Java 9+): - Arrays.asList(): fixed size but set() works, null elements allowed, and changes to the backing array show…
double/float follow the IEEE 754 binary standard. 0.1 and 0.2 are repeating fractions in binary, so they are stored only approximately; their sum is 0.30000000000000004. For money, pick one of two options: 1. BigDecimal constructed from a String, never from a double: 2. Integer minor…
Before Java 8, all entries in the same bucket lived on a linked list, so worst-case lookup was O(n). Since Java 8 HashMap converts a bucket into a red-black tree once it grows too long: - TREEIFYTHRESHOLD = 8: a bucket with 8 or more…
The entry becomes unreachable even though it is still in the map. HashMap computes the bucket once at put time; if you later change a field that feeds hashCode(), the new hash points at a different bucket, so get() looks in the wrong place. Consequences:…
Use LinkedHashMap in access-order mode and override removeEldestEntry. How it works: - The three-arg constructor with accessOrder = true moves every accessed entry (get/put) to the end of the internal linked list, so the head is the least recently used entry. - After each put,…
The two pitfalls are duplicate keys and null values. Both throw an exception instead of being ignored silently. Duplicate keys throw IllegalStateException. The two-arg overload has no collision policy, so it just throws: Fix it with the third argument — the merge function — which…
It cannot be reused. Each stream supports exactly one terminal operation; a second call throws IllegalStateException: stream has already been operated upon or closed. It "does not run" because streams are lazy: filter, map, peek, and sorted only describe the pipeline. Without a terminal operation…
try-with-resources (Java 7) closes every resource declared in the header automatically, in reverse declaration order, even when an exception occurs. The key difference shows up when both the try block and close() throw: A suppressed exception is that swallowed one: it is attached to the…
String is immutable, so every + produces a new string and copies the previous content. Across n loop iterations the total copying is O(n²). What the compiler emits: - Before Java 9: javac rewrote a + b + c into a chain of StringBuilder.append(...) calls.…
The Thread.State enum defines six states: - NEW — constructed but start() not yet called. - RUNNABLE — running or waiting for a CPU slot. The JVM merges both; there is no separate "RUNNING" state. - BLOCKED — waiting for a monitor lock to enter…
They differ in the return value and in how errors propagate. Runnable.run() Callable.call() --------- Returns void V (generic) Checked exceptions cannot throw throws Exception Submitting execute() or submit() submit() only Result none Future<V The practical gotcha: if a task throws, execute(Runnable) routes the error to…
The JVM only waits for user threads. When the last user thread finishes, the JVM exits and kills any running daemon threads immediately. The key consequence: a daemon is stopped abruptly, so finally blocks and shutdown logic may never run. Never use a daemon for…
An object becomes eligible when no path reaches it from any GC root. GC roots include: local variables on live thread stacks, static fields, JNI references, and the running threads themselves. This is reachability, not reference counting. So two objects referencing each other with nothing…
Both provide mutual exclusion and both are reentrant. They differ in how much control you get. synchronized ReentrantLock --------- Release automatic on block exit must unlock() in finally Try to acquire no tryLock(), tryLock(timeout) Cancellable wait no lockInterruptibly() Fairness not configurable new ReentrantLock(true) Wait queues…
They differ in which object holds the monitor. - A synchronized instance method locks on this. Each instance has its own lock. - A static synchronized method locks on the Counter.class object. That is a single lock for the whole class, shared by all instances.…
Java has no safe way to kill a thread forcibly. The official mechanism is cooperative: send a signal and let the thread exit at a point it chooses. Thread.stop() was deprecated long ago and now throws UnsupportedOperationException because it releases every monitor the thread holds,…
Start from the task's wait-to-compute ratio; Brian Goetz's reference formula is: - Ncpu = Runtime.getRuntime().availableProcessors() - Ucpu = target CPU utilization (0..1) - W/C = wait time / compute time CPU-bound tasks (encryption, computation, parsing): W/C is near 0 → size ≈ Ncpu (or Ncpu…
The main parameters: corePoolSize, maximumPoolSize, keepAliveTime, workQueue, threadFactory, RejectedExecutionHandler. The order in which a new task is handled is often misunderstood: 1. Running threads < corePoolSize → create a new thread. 2. Core is full → enqueue into workQueue. 3. Queue is full → only…
The three combinators differ by the shape of the function they take: - thenApply(Function<T, U) — transforms the result synchronously. Like map. - thenCompose(Function<T, CompletionStage<U) — the function returns another future and the result is flattened. Like flatMap. Using thenApply here yields a nested CompletableFuture<CompletableFuture<U.…
Metaspace holds class metadata (class structure, methods, resolved constant pool), replacing PermGen as of Java 8 (JEP 122). PermGen (≤ Java 7) Metaspace (Java 8+) --------- Location inside the heap native memory, off-heap Size fixed via -XX:MaxPermSize grows automatically, unbounded by default Flag -XX:PermSize -XX:MaxMetaspaceSize…
Java suits backends for three reasons: a stable JVM with more than 25 years in production, a Spring ecosystem that already solves most web/enterprise problems, and static typing that keeps a large, many-hands codebase under control. The question checks whether you understand your tool or…
HashMap is not thread-safe but is the fastest; Hashtable is thread-safe by making every method synchronized (one lock for the whole map — slow, a legacy class); ConcurrentHashMap is thread-safe with very fine-grained locking, so many threads can read/write in parallel. New code that needs…
An array is a language construct with a fixed size set at creation and can hold primitives (int[]); ArrayList is a Collections Framework class that resizes itself, holds only objects (ArrayList<Integer), and internally is backed by an array. Array ArrayList --------- Size Fixed, arr.length Grows,…
Unit testing a service = run its own logic while every dependency (repositories, external API clients) is replaced by a mock. Mockito does three things: creates mocks (@Mock), defines what a mock returns (stubbing: when(...).thenReturn(...)), and checks that the service called its dependencies correctly (verify).…
Multithreading is about where things run: splitting work across threads to run in parallel (ExecutorService manages a thread pool). Asynchronous is about how you wait: start a task and do not stand there waiting; register "when it finishes, do this next". CompletableFuture (Java 8) is…
A Java enum is a special class: the compiler makes it implicitly extend java.lang.Enum, and each constant (PENDING, PAID...) is a single public static final instance created when the class loads. Because it is a class, an enum can have fields, a constructor, methods and…
A List is an ordered sequence that allows duplicates and index access; a Set is a collection with no duplicates and no index. The deciding questions: may the data contain duplicates, and do you need "the i-th element" or "does it exist"? List (ArrayList) Set…