Core Java Interview Questions and Answers (2026)
Preparing for a Java developer interview? This guide covers 150+ Core Java interview questions with detailed answers — from beginner to advanced level — to help you crack rounds at TCS, Infosys, Wipro, Cognizant, Accenture, Goldman Sachs, JP Morgan, and product startups.
Whether you are a fresher applying for your first Java role or an experienced developer targeting senior positions, these questions cover what interviewers actually ask: OOP principles, collections internals, multithreading, Java 8 features, JVM memory model, exception handling, generics, and design patterns.
Topics covered:
- Basic Java — JDK vs JRE vs JVM, platform independence, String pool, wrapper classes, pass-by-value
- Object-Oriented Programming — inheritance, polymorphism, abstraction, encapsulation, interfaces
- Exception Handling — checked vs unchecked, try-with-resources, custom exceptions, propagation
- Collections Framework — ArrayList vs LinkedList, HashMap internals, fail-fast, Comparable vs Comparator
- Multithreading — thread lifecycle, synchronization, deadlock, volatile, thread pool, Callable
- Java 8+ Features — lambdas, Stream API, Optional, functional interfaces, method references, Date/Time API
- JVM and Memory — heap vs stack, garbage collection, GC algorithms, memory leaks, reference types
- Advanced Topics — reflection, generics, annotations, ClassLoader, serialization, design patterns
Who this is for: Java freshers (0-2 years), mid-level developers (2-5 years), and senior engineers preparing for full-stack or backend-focused rounds.
1. Basic Java Concepts
Q1. What is Java and what are its main features?
Java is a high-level, object-oriented, platform-independent programming language developed by Sun Microsystems (now Oracle) in 1995. It follows the principle "Write Once, Run Anywhere" (WORA).
Key features:
- Platform independent — Java compiles to bytecode that runs on any JVM
- Object-oriented — everything modelled as objects with encapsulation, inheritance, polymorphism
- Strongly typed — all variables must be declared with a data type
- Automatic memory management — garbage collector handles deallocation
- Multithreaded — built-in support for concurrent programming
- Robust — strong type checking, exception handling, no pointer arithmetic
- Secure — bytecode verifier, no direct memory access
- Distributed — supports RMI, sockets, and web services natively
Q2. Explain the difference between JDK, JRE, and JVM.
| Component | Full Form | Contents | Who needs it |
|---|---|---|---|
| JVM | Java Virtual Machine | Bytecode interpreter, JIT compiler, GC, memory manager | Runtime — embedded inside JRE |
| JRE | Java Runtime Environment | JVM + core class libraries (java.lang, java.util) | End users running Java apps |
| JDK | Java Development Kit | JRE + compiler (javac) + debugger (jdb) + tools (javadoc, jar) | Developers writing and compiling Java |
In short: JDK contains JRE, which contains JVM.
Q3. What is platform independence in Java?
Java achieves platform independence through its two-step compilation model:
- The Java compiler (
javac) converts.javasource code into bytecode (.classfiles) - The JVM on each OS interprets and executes that bytecode using a JIT (Just-In-Time) compiler
Since every OS has its own JVM implementation, the same .class file runs on Windows, Linux, and macOS without recompilation — this is "Write Once, Run Anywhere."
Q4. Is Java pass-by-value or pass-by-reference?
Java is strictly pass-by-value — always. For objects, the value passed is a copy of the reference (memory address), not the object itself.
void changeValue(int x) { x = 100; } // primitive — caller unaffected
void changeName(Person p) { p.name = "Bob"; } // modifies the object — visible to caller
void reassign(Person p) { p = new Person(); } // reassign — caller unaffected
Q5. What is a constructor? What are its types?
A constructor has the same name as the class, no return type, and is called automatically when an object is created with new.
Types:
1. Default (no-arg) constructor — compiler provides one if none is defined.
2. Parameterised constructor:
class Dog {
String name;
Dog(String name) { this.name = name; }
}
3. Copy constructor (must write manually in Java):
Dog(Dog other) { this.name = other.name; }
Constructor chaining: Use this() to call another constructor in the same class, or super() to call the parent constructor. Both must be the first statement.
Q6. What is the difference between final, finally, and finalize?
| Keyword | Context | Purpose |
|---|---|---|
| final | Variable, method, or class | Variable: cannot be reassigned. Method: cannot be overridden. Class: cannot be subclassed. |
| finally | try-catch block | Always executes after try/catch — used for cleanup (closing streams, connections) |
| finalize() | Method in Object class | Called by GC before collecting an object. Deprecated since Java 9 — use try-with-resources instead |
Q7. What is the difference between throw and throws?
| throw | throws | |
|---|---|---|
| Purpose | Actually throws an exception instance | Declares that a method may throw an exception |
| Location | Inside method body | In the method signature |
| Example | throw new IOException("not found") | void read() throws IOException |
Q8. What is the difference between == and .equals()?
| == | .equals() | |
|---|---|---|
| Compares | Reference (memory address) | Content/value (depends on override) |
| Primitives | Compares actual values | Not applicable |
| Objects | true only if same object in memory | true if content is logically equal |
String a = new String("hello");
String b = new String("hello");
System.out.println(a == b); // false — different objects
System.out.println(a.equals(b)); // true — same content
Q9. What is the difference between String, StringBuilder, and StringBuffer?
| String | StringBuilder | StringBuffer | |
|---|---|---|---|
| Mutability | Immutable | Mutable | Mutable |
| Thread-safe | Yes (immutable) | No | Yes (synchronized) |
| Performance | Slow for concatenation | Fastest | Slower than StringBuilder |
| Use when | Value doesn't change | Single-threaded string building | Multi-threaded string building |
Q10. Why is String immutable in Java?
Strings are stored as private final char[] (or byte[] in Java 9+) with no methods that modify the array after construction.
Benefits:
- String pool efficiency — multiple variables safely share the same literal
- Security — passwords and file paths cannot be altered after passing
- Thread safety — immutable objects can be shared across threads without synchronization
- Hashcode caching — hash computed once and cached; makes Strings efficient HashMap keys
Q11. What is the String pool?
The String pool is a special heap area where the JVM stores string literals to avoid duplicate objects.
String a = "hello"; // stored in pool
String b = "hello"; // reuses same pool entry
String c = new String("hello"); // new object on heap, NOT in pool
System.out.println(a == b); // true — same pool reference
System.out.println(a == c); // false — c is on heap
System.out.println(a == c.intern()); // true — intern() brings c into pool
Q12. What are wrapper classes and autoboxing?
Wrapper classes wrap primitive types into objects for use in collections and generics.
| Primitive | Wrapper | Primitive | Wrapper |
|---|---|---|---|
| int | Integer | float | Float |
| long | Long | boolean | Boolean |
| double | Double | char | Character |
Autoboxing/Unboxing — Java automatically converts between primitives and wrappers:
Integer x = 5; // autoboxing: int to Integer
int y = x; // unboxing: Integer to int
list.add(10); // autoboxing happens automatically
Q13. What is the difference between stack and heap memory?
| Stack | Heap | |
|---|---|---|
| Stores | Method call frames, local variables, references | All objects and instance variables |
| Scope | Each thread has its own stack | Shared across all threads |
| Size | Small (512KB-2MB per thread) | Large (configured via -Xmx) |
| Allocation | LIFO — auto on method enter/exit | Dynamic — GC reclaims unreachable objects |
| Error | StackOverflowError | OutOfMemoryError |
Q14. What is the difference between shallow copy and deep copy?
Shallow copy copies field values. For reference fields, it copies the reference — both copies point to the same nested object.
Deep copy recursively copies all nested objects so the copy is fully independent.
class Address { String city; }
class Person implements Cloneable {
String name;
Address address;
// Shallow — address reference shared between original and copy
public Person shallowCopy() throws CloneNotSupportedException {
return (Person) super.clone();
}
// Deep — fully independent
public Person deepCopy() throws CloneNotSupportedException {
Person copy = (Person) super.clone();
copy.address = new Address();
copy.address.city = this.address.city;
return copy;
}
}
2. Object-Oriented Programming
Q15. What are the four pillars of OOP?
| Pillar | Definition | Java example |
|---|---|---|
| Encapsulation | Bundling data and methods; hiding internal state via access modifiers | private fields + public getters/setters |
| Inheritance | A child class acquires properties and behaviours of a parent class | class Dog extends Animal |
| Polymorphism | One interface, many implementations | Method overriding, method overloading |
| Abstraction | Hiding implementation details, exposing only what is necessary | abstract class, interface |
Q16. Why doesn't Java support multiple inheritance through classes?
Java avoids the Diamond Problem: if class C inherits from both A and B, and both have the same method display(), which version does C inherit? This ambiguity could cause unpredictable behaviour.
Java's solution:
- Classes: single inheritance only (
extendsone class) - Interfaces: multiple implementation allowed (
implements A, B, C) — default method conflicts must be explicitly resolved
interface A { default void greet() { System.out.println("A"); } }
interface B { default void greet() { System.out.println("B"); } }
class C implements A, B {
public void greet() { A.super.greet(); } // must resolve explicitly
}
Q17. What is the difference between method overloading and overriding?
| Overloading | Overriding | |
|---|---|---|
| Definition | Same method name, different parameters in the SAME class | Same method name and parameters in PARENT and CHILD class |
| Polymorphism type | Compile-time (static) | Runtime (dynamic) |
| Return type | Can differ | Must be same or covariant |
| Access modifier | Can be anything | Cannot be more restrictive than parent |
Q18. What is the difference between abstract class and interface?
| Abstract Class | Interface | |
|---|---|---|
| Methods | Abstract + concrete methods | Abstract; default/static allowed (Java 8+) |
| Variables | Any type of fields | public static final constants only |
| Constructor | Can have constructors | Cannot have constructors |
| Inheritance | Single inheritance (extends one) | Multiple implementation (implements many) |
| Use when | Shared code/state among related classes | Contract/capability across unrelated classes |
Q19. What is composition vs inheritance? Which is preferred?
- Inheritance — "is-a" relationship:
Dog extends Animal - Composition — "has-a" relationship:
Car has Engine
// Composition (preferred)
class Engine { void start() {} }
class Car {
private Engine engine = new Engine(); // Car HAS-A Engine
void startCar() { engine.start(); }
}
Prefer composition because it gives looser coupling, avoids the fragile base class problem, and is more flexible at runtime.
Q20. What is the Singleton pattern? How to make it thread-safe?
Singleton ensures only one instance of a class exists.
Thread-safe double-checked locking:
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) instance = new Singleton();
}
}
return instance;
}
}
Best practice — Enum Singleton:
public enum Singleton { INSTANCE; }
Thread-safe, serialization-safe, and reflection-proof by default.
Q21. What is runtime polymorphism?
Runtime polymorphism (dynamic dispatch) — the method to be called is resolved at runtime based on the actual object type, not the reference type.
class Animal { void sound() { System.out.println("..."); } }
class Dog extends Animal { void sound() { System.out.println("Woof"); } }
class Cat extends Animal { void sound() { System.out.println("Meow"); } }
Animal a = new Dog(); // upcasting
a.sound(); // "Woof" — resolved at runtime
3. Exception Handling
Q22. What is the Java exception hierarchy?
Throwable
├── Error (JVM-level — do NOT catch: OutOfMemoryError, StackOverflowError)
└── Exception
├── RuntimeException (unchecked — don't require try-catch)
│ ├── NullPointerException
│ ├── ArrayIndexOutOfBoundsException
│ └── IllegalArgumentException
└── Checked exceptions (must declare or catch)
├── IOException
├── SQLException
└── ClassNotFoundException
Q23. What is the difference between checked and unchecked exceptions?
| Checked | Unchecked | |
|---|---|---|
| Checked at | Compile time | Runtime |
| Extends | Exception (not RuntimeException) | RuntimeException |
| Must handle? | Yes — try-catch or throws required | No — optional |
| Examples | IOException, SQLException | NullPointerException, ArrayIndexOutOfBoundsException |
| Cause | External factors (file not found, DB down) | Programming bugs |
Q24. What is try-with-resources?
Introduced in Java 7 — automatically closes any AutoCloseable resource when the try block exits.
// Java 7+ — automatic close
try (FileReader fr = new FileReader("file.txt");
BufferedReader br = new BufferedReader(fr)) {
String line = br.readLine();
} // fr and br closed automatically in reverse order
Q25. What is exception propagation?
When an exception is thrown and not caught in the current method, it propagates up the call stack to the caller, and so on, until caught or the JVM terminates.
void c() { throw new RuntimeException("Error"); }
void b() { c(); } // propagates up
void a() { b(); } // propagates up
public static void main(String[] args) {
try { a(); }
catch (RuntimeException e) { System.out.println("Caught: " + e.getMessage()); }
}
Q26. How do you create a custom exception?
// Custom checked exception
public class InsufficientFundsException extends Exception {
private double shortfall;
public InsufficientFundsException(double shortfall) {
super("Insufficient funds. Short by: " + shortfall);
this.shortfall = shortfall;
}
public double getShortfall() { return shortfall; }
}
// Usage
public void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) throw new InsufficientFundsException(amount - balance);
balance -= amount;
}
Extend RuntimeException for unchecked custom exceptions.
4. Collections Framework
Q27. What is the Java Collections Framework?
The Java Collections Framework (JCF) provides interfaces, implementations, and algorithms for storing and manipulating groups of objects.
| Interface | Duplicates | Ordered | Common implementations |
|---|---|---|---|
| List | Yes | Yes (by index) | ArrayList, LinkedList, Vector |
| Set | No | No (HashSet) / Yes (LinkedHashSet, TreeSet) | HashSet, LinkedHashSet, TreeSet |
| Map | Keys: No, Values: Yes | No (HashMap) / Yes (LinkedHashMap, TreeMap) | HashMap, LinkedHashMap, TreeMap |
| Queue | Yes | FIFO | LinkedList, PriorityQueue, ArrayDeque |
Q28. What is the difference between ArrayList and LinkedList?
| ArrayList | LinkedList | |
|---|---|---|
| Internal structure | Dynamic array (Object[]) | Doubly-linked list of nodes |
| get(i) — random access | O(1) | O(n) — must traverse |
| add/remove at end | O(1) amortised | O(1) |
| add/remove in middle | O(n) — shifts elements | O(1) after finding the node |
| Memory | Less overhead | More (prev/next pointers per node) |
| Use when | Frequent reads by index | Frequent insertions/deletions |
Q29. How does HashMap work internally?
HashMap is backed by an array of buckets (Node[] table).
When you call put(key, value):
- Compute
hashCode()of the key - Apply secondary hash to get bucket index:
index = hash & (capacity - 1) - If bucket is empty — place the entry
- If collision — compare with
equals():- Equal key: update value
- Different key: add to linked list (or Red-Black tree if bucket size > 8, Java 8+)
Resize (rehash): When size > capacity x loadFactor (default 0.75), the array doubles.
Q30. What is the difference between HashMap and ConcurrentHashMap?
| HashMap | ConcurrentHashMap | |
|---|---|---|
| Thread-safe | No | Yes |
| Locking | None | Bucket-level CAS (Java 8+) |
| Null keys | One null key allowed | No null keys or values |
| Iteration | Fail-fast (ConcurrentModificationException) | Weakly consistent — no exception |
Q31. What is fail-fast vs fail-safe iteration?
Fail-fast (ArrayList, HashMap): throws ConcurrentModificationException if the collection is modified during iteration.
Fail-safe (CopyOnWriteArrayList, ConcurrentHashMap): iterates over a snapshot — no exception during concurrent modification.
// Fail-fast — throws ConcurrentModificationException
for (String s : list) { list.remove(s); } // ERROR
// Safe removal
Iterator<String> it = list.iterator();
while (it.hasNext()) { it.next(); it.remove(); } // OK
Q32. What is the difference between Comparable and Comparator?
| Comparable | Comparator | |
|---|---|---|
| Package | java.lang | java.util |
| Method | compareTo(T o) | compare(T o1, T o2) |
| Implemented in | The class itself | Separate class or lambda |
| Use when | Natural/default ordering | Multiple/custom orderings |
// Comparable — natural order by marks
class Student implements Comparable<Student> {
int marks;
public int compareTo(Student s) { return this.marks - s.marks; }
}
// Comparator — sort by name
students.sort(Comparator.comparing(s -> s.name));
5. Multithreading
Q33. What are the different ways to create threads?
1. Implement Runnable (preferred):
Thread t = new Thread(() -> System.out.println("Running"));
t.start();
2. Extend Thread:
class MyThread extends Thread {
public void run() { System.out.println("Running"); }
}
new MyThread().start();
3. ExecutorService (recommended for production):
ExecutorService pool = Executors.newFixedThreadPool(4);
pool.submit(() -> processTask());
pool.shutdown();
Q34. What are the thread lifecycle states?
| State | Description |
|---|---|
| NEW | Thread created but start() not called |
| RUNNABLE | Executing or ready to execute (waiting for CPU) |
| BLOCKED | Waiting to acquire a monitor lock |
| WAITING | Waiting indefinitely — wait(), join() with no timeout |
| TIMED_WAITING | Waiting for a specified time — sleep(ms), wait(ms) |
| TERMINATED | run() has completed |
Q35. What is synchronization? Why is it needed?
When multiple threads access shared mutable data, race conditions occur. Synchronization ensures only one thread executes a critical section at a time.
class Counter {
private int count = 0;
public synchronized void increment() { count++; } // method-level lock
public void decrement() {
synchronized(this) { count--; } // block-level (finer granularity)
}
}
Q36. What is deadlock? How do you avoid it?
Deadlock: two threads permanently blocked, each waiting for a lock held by the other.
Thread 1: holds Lock A, waiting for Lock B
Thread 2: holds Lock B, waiting for Lock A → deadlock
Prevention:
- Always acquire multiple locks in the same fixed order
- Use
tryLock()with timeout fromjava.util.concurrent.locks - Minimize scope of synchronized blocks
- Prefer
java.util.concurrentutilities over rawsynchronized
Q37. What is the volatile keyword?
volatile ensures a variable is always read from and written to main memory — not a thread-local CPU cache. Guarantees visibility but NOT atomicity.
class Server {
volatile boolean running = true;
void stop() { running = false; }
void serve() { while (running) { /* always reads latest value */ } }
}
For compound operations like count++, use AtomicInteger — not just volatile.
Q38. What is the difference between wait() and sleep()?
| wait() | sleep() | |
|---|---|---|
| Class | Object | Thread |
| Releases lock? | Yes | No — keeps the lock |
| Woken by | notify() or notifyAll() | Time expiry or interrupt |
| Must be in | synchronized block | Anywhere |
| Purpose | Inter-thread communication | Pause execution for fixed time |
Q39. What is the difference between Callable and Runnable?
| Runnable | Callable<V> | |
|---|---|---|
| Method | void run() | V call() throws Exception |
| Return value | None | Returns V |
| Checked exceptions | Cannot throw | Can throw |
| Used with | Thread, ExecutorService | ExecutorService — returns Future<V> |
Future<Integer> future = pool.submit(() -> { Thread.sleep(1000); return 42; });
System.out.println(future.get()); // blocks until done — prints 42
6. Java 8+ Features
Q40. What are lambda expressions?
A lambda is a concise anonymous function implementing a functional interface (one abstract method).
// Before Java 8
Runnable r = new Runnable() { public void run() { System.out.println("Hi"); } };
// Java 8 lambda
Runnable r = () -> System.out.println("Hi");
// With parameters
Comparator<String> comp = (a, b) -> a.compareTo(b);
Q41. What are functional interfaces?
A functional interface has exactly one abstract method. Built-in ones in java.util.function:
| Interface | Method | Description |
|---|---|---|
| Predicate<T> | boolean test(T t) | Test a condition — returns true/false |
| Function<T,R> | R apply(T t) | Transform T to R |
| Consumer<T> | void accept(T t) | Consume T, no return |
| Supplier<T> | T get() | Supply a T, no input |
| BiFunction<T,U,R> | R apply(T t, U u) | Two inputs, one output |
Q42. What is the Stream API?
Streams provide a declarative functional-style way to process collections. Operations are lazy — executed only when a terminal operation triggers the pipeline.
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
int result = numbers.stream()
.filter(n -> n % 2 == 0) // intermediate — lazy
.map(n -> n * n) // intermediate — lazy
.reduce(0, Integer::sum); // terminal — triggers execution
System.out.println(result); // 4 + 16 + 36 = 56
Streams don't modify the original collection and can only be consumed once.
Q43. What is the Optional class?
Optional<T> is a container that may or may not hold a non-null value — designed to eliminate NullPointerException.
Optional<String> name = Optional.of("Alice");
Optional<String> nullable = Optional.ofNullable(null);
name.isPresent(); // true
name.get(); // "Alice"
nullable.orElse("N/A"); // "N/A"
name.map(String::toUpperCase).orElse(""); // "ALICE"
name.ifPresent(System.out::println); // prints "Alice"
Use Optional as return types only — not as method parameters or class fields.
Q44. What is method reference?
Method references are shorthand for lambdas that call a single method:
| Type | Syntax | Example |
|---|---|---|
| Static method | Class::staticMethod | Integer::parseInt |
| Instance (specific object) | object::instanceMethod | System.out::println |
| Instance (arbitrary object) | Class::instanceMethod | String::toUpperCase |
| Constructor | Class::new | ArrayList::new |
Q45. What is the difference between map() and flatMap()?
- map() — transforms each element 1-to-1; result may be nested
- flatMap() — transforms each element to a stream and flattens into one stream
List<List<Integer>> nested = Arrays.asList(
Arrays.asList(1, 2), Arrays.asList(3, 4)
);
// flatMap — flattens to [1, 2, 3, 4]
nested.stream().flatMap(List::stream).collect(Collectors.toList());
7. JVM and Memory Management
Q46. How is JVM memory organised?
| Memory area | Contents | Per thread? |
|---|---|---|
| Heap | All objects (Young Gen + Old Gen) | Shared |
| Stack | Method frames, local variables, references | Per thread |
| Metaspace (Java 8+) | Class metadata (replaces PermGen) | Shared |
| Code Cache | JIT-compiled native code | Shared |
| PC Register | Address of current instruction | Per thread |
Q47. What is garbage collection? How does generational GC work?
The Garbage Collector automatically removes objects no longer reachable, freeing heap memory.
Generational GC:
- Young Generation (Eden + Survivor spaces): newly created objects — collected frequently (Minor GC, fast)
- Old Generation: long-lived objects — collected infrequently (Major GC, slower)
GC algorithms:
| GC | Best for | Default? |
|---|---|---|
| Serial GC | Small, single-threaded apps | No |
| Parallel GC | Throughput-focused multi-threaded | Java 8 default |
| G1 GC | Large heaps, predictable pause times | Java 9+ default |
| ZGC / Shenandoah | Sub-millisecond pauses | Java 11+ opt-in |
Q48. What are the different types of references?
| Type | GC behaviour | Use case |
|---|---|---|
| Strong | Not collected while reference exists | All normal objects |
| Soft (SoftReference) | Collected only when memory is low | Memory-sensitive caches |
| Weak (WeakReference) | Collected at next GC cycle | WeakHashMap keys, canonicalized maps |
| Phantom (PhantomReference) | Enqueued in ReferenceQueue after collection | Post-mortem cleanup actions |
8. Advanced Concepts
Q49. What is reflection in Java?
Reflection lets a program inspect and manipulate classes, methods, fields, and constructors at runtime — even private ones.
Class<?> clazz = Class.forName("com.example.Person");
// Invoke a private method
Method m = clazz.getDeclaredMethod("secretMethod");
m.setAccessible(true);
m.invoke(instance);
// Get/set a private field
Field f = clazz.getDeclaredField("name");
f.setAccessible(true);
f.set(instance, "Bob");
Used by Spring/Hibernate for DI, JUnit for test discovery. Slower than direct calls — avoid in hot paths.
Q50. What are generics in Java?
Generics add type parameters to classes and methods, enabling type safety without casting.
// Without generics — ClassCastException risk
List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0);
// With generics — type-safe, no cast needed
List<String> list = new ArrayList<>();
list.add("hello");
String s = list.get(0);
Bounded type parameters:
<T extends Number>— T must be Number or subtype (upper bound)<T super Integer>— T must be Integer or supertype (lower bound)<?>— unknown wildcard
Q51. What is serialization? What is serialVersionUID?
Serialization converts an object to a byte stream for saving or sending over a network.
class Person implements Serializable {
private static final long serialVersionUID = 1L;
String name;
transient String password; // NOT serialized
}
// Serialize
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("p.dat"))) {
oos.writeObject(person);
}
// Deserialize
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("p.dat"))) {
Person p = (Person) ois.readObject();
}
If serialVersionUID doesn't match during deserialization (class changed), an InvalidClassException is thrown.
Q52. What is the difference between ClassNotFoundException and NoClassDefFoundError?
| ClassNotFoundException | NoClassDefFoundError | |
|---|---|---|
| Type | Checked Exception | Error (unchecked) |
| When thrown | Class.forName() can't find the class at runtime | Class present at compile time but missing at runtime |
| Recovery | Can be caught and handled | Usually fatal |
Q53. What are annotations? How do you create a custom one?
Annotations are metadata added to code, processed at compile time or runtime by frameworks.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Benchmark {
String description() default "";
}
// Usage
@Benchmark(description = "measures latency")
public void processOrder() { ... }
// Read at runtime
Method m = MyService.class.getMethod("processOrder");
Benchmark b = m.getAnnotation(Benchmark.class);
System.out.println(b.description());
9. Design Patterns
Q54. What is the Factory Pattern?
Factory Method defines an interface for creating objects, letting a factory decide which class to instantiate.
interface Shape { void draw(); }
class Circle implements Shape { public void draw() { System.out.println("Circle"); } }
class Rectangle implements Shape { public void draw() { System.out.println("Rectangle"); } }
class ShapeFactory {
static Shape create(String type) {
return switch (type) {
case "circle" -> new Circle();
case "rectangle" -> new Rectangle();
default -> throw new IllegalArgumentException("Unknown: " + type);
};
}
}
Q55. What is the Builder Pattern?
Builder separates construction of complex objects from their representation — avoids telescoping constructors.
class User {
private final String name;
private final String email;
private User(Builder b) { name = b.name; email = b.email; }
static class Builder {
String name, email;
Builder name(String n) { name = n; return this; }
Builder email(String e) { email = e; return this; }
User build() { return new User(this); }
}
}
User user = new User.Builder().name("Alice").email("alice@test.com").build();
Q56. What is the Observer Pattern?
Observer defines a one-to-many dependency: when the subject changes, all observers are notified.
interface Observer { void update(String event); }
class EventBus {
private List<Observer> observers = new ArrayList<>();
void subscribe(Observer o) { observers.add(o); }
void publish(String event) { observers.forEach(o -> o.update(event)); }
}
EventBus bus = new EventBus();
bus.subscribe(e -> System.out.println("Logger: " + e));
bus.subscribe(e -> System.out.println("Email: " + e));
bus.publish("USER_SIGNUP");
10. JDBC and Miscellaneous
Q57. What is JDBC? What are the key interfaces?
JDBC (Java Database Connectivity) is the standard API for connecting Java apps to relational databases.
try (Connection conn = DriverManager.getConnection(URL, USER, PASS);
PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE id = ?")) {
ps.setInt(1, 42);
ResultSet rs = ps.executeQuery();
while (rs.next()) { System.out.println(rs.getString("name")); }
}
Key interfaces: Connection, Statement, PreparedStatement, ResultSet, CallableStatement
Q58. What is the difference between Statement and PreparedStatement?
| Statement | PreparedStatement | |
|---|---|---|
| SQL compilation | Compiled on every execute | Compiled once, reused |
| Performance | Slower for repeated queries | Faster — DB caches execution plan |
| SQL injection | Vulnerable | Safe — parameters are escaped |
| Use when | Dynamic SQL, no parameters | Parameterised or repeated queries |
Q59. What is the transient keyword?
transient marks a field to be excluded from serialization. Transient fields are set to default values on deserialization.
class User implements Serializable {
String username;
transient String password; // security-sensitive — not serialized
transient Connection conn; // cannot serialize a live DB connection
}
Q60. What is the difference between HashMap and Hashtable?
| HashMap | Hashtable | |
|---|---|---|
| Thread-safe | No | Yes (synchronized) |
| Null keys/values | One null key, multiple null values | No null keys or values |
| Performance | Faster | Slower (synchronization overhead) |
| Status | Preferred | Legacy — use ConcurrentHashMap instead |
Q61. What is connection pooling? Why is it important?
Connection pooling maintains a cache of pre-opened database connections that are reused instead of creating a new one per request.
Creating a DB connection is expensive (~50-200ms). A pool dramatically reduces latency and prevents resource exhaustion.
Popular pools: HikariCP (fastest, default in Spring Boot), Apache DBCP, c3p0
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost/mydb");
config.setMaximumPoolSize(20);
HikariDataSource ds = new HikariDataSource(config);
Connection conn = ds.getConnection(); // borrowed from pool, returned on close
Q62. What is a marker interface?
A marker interface is an interface with no methods or fields — it just marks a class to indicate it has a certain capability or property. The JVM or framework checks instanceof to decide behaviour.
Examples:
Serializable— marks a class as serializableCloneable— marks a class as supportingclone()RandomAccess— signals that a List supports fast random access
class Person implements Serializable {} // marked — JVM will serialize it
if (obj instanceof Serializable) {
// safe to serialize
}
Java 5+ annotations (@Entity, @FunctionalInterface) are the modern replacement for marker interfaces.
Q63. What is the difference between int and Integer?
| int | Integer | |
|---|---|---|
| Type | Primitive | Object (wrapper class) |
| Default value | 0 | null |
| Memory | 4 bytes on stack | 16+ bytes on heap |
| Collections | Cannot be used (no generics with primitives) | Can be stored in List<Integer> |
| Null | Cannot be null | Can be null (NullPointerException risk on unboxing) |
Integer cache: Java caches Integer objects from -128 to 127. Comparing cached values with == gives true; outside that range it's false:
Integer a = 100, b = 100; System.out.println(a == b); // true (cached)
Integer c = 200, d = 200; System.out.println(c == d); // false (not cached)
Q64. What is type casting in Java?
Widening (implicit): smaller type to larger type — no data loss, done automatically.
int i = 10;
long l = i; // int → long, automatic
double d = l; // long → double, automatic
Narrowing (explicit): larger type to smaller type — may lose data, requires explicit cast.
double d = 9.99;
int i = (int) d; // 9 — decimal part lost
Object casting:
Animal a = new Dog(); // upcasting — implicit
Dog d = (Dog) a; // downcasting — explicit, may throw ClassCastException
if (a instanceof Dog) { Dog d = (Dog) a; } // safe downcasting
Q65. What are the different types of loops in Java?
1. for loop — when the number of iterations is known:
for (int i = 0; i < 5; i++) { System.out.println(i); }
2. while loop — when the condition is checked before each iteration:
int i = 0;
while (i < 5) { System.out.println(i++); }
3. do-while loop — executes at least once; condition checked after:
int i = 0;
do { System.out.println(i++); } while (i < 5);
4. enhanced for-each loop — iterates over arrays/Iterable collections:
int[] arr = {1, 2, 3};
for (int n : arr) { System.out.println(n); }
Q66. What are access modifiers in Java?
| Modifier | Same class | Same package | Subclass (other package) | Other packages |
|---|---|---|---|---|
| private | Yes | No | No | No |
| (default) | Yes | Yes | No | No |
| protected | Yes | Yes | Yes | No |
| public | Yes | Yes | Yes | Yes |
Q67. What is the static keyword in Java?
static members belong to the class rather than any specific instance.
- Static variable — shared across all instances; one copy per class
- Static method — can be called without creating an object; cannot access instance fields
- Static block — executed once when the class is loaded; used for static initialization
- Static nested class — inner class that doesn't need an outer class instance
class MathUtil {
static final double PI = 3.14159; // static constant
static double circleArea(double r) { return PI * r * r; } // static method
}
double area = MathUtil.circleArea(5); // no object needed
11. File I/O and Serialization
Q68. What is the difference between FileInputStream and FileReader?
| FileInputStream | FileReader | |
|---|---|---|
| Reads | Raw bytes | Characters (text) |
| Use for | Binary files (images, audio, PDFs) | Text files (.txt, .csv, .json) |
| Encoding | No encoding — raw bytes | Uses platform/specified charset |
| Extends | InputStream | Reader (InputStreamReader) |
For text files, wrap in BufferedReader for efficiency:
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
String line;
while ((line = br.readLine()) != null) { System.out.println(line); }
}
Q69. What is the difference between Reader/Writer and InputStream/OutputStream?
| InputStream / OutputStream | Reader / Writer | |
|---|---|---|
| Data unit | Byte (8-bit) | Character (16-bit Unicode) |
| Best for | Binary data | Text data |
| Key classes | FileInputStream, FileOutputStream, BufferedInputStream | FileReader, FileWriter, BufferedReader, PrintWriter |
Q70. What is externalization in Java?
Externalization (Externalizable interface) gives full control over serialization — you implement writeExternal() and readExternal() to define exactly what gets serialized.
class Config implements Externalizable {
String host;
int port;
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(host);
out.writeInt(port);
}
public void readExternal(ObjectInput in) throws IOException {
host = in.readUTF();
port = in.readInt();
}
}
Serializable vs Externalizable:
Serializable— JVM handles everything automatically (via reflection); slowerExternalizable— you control exactly what is written; faster, more compact
Q71. What is NIO (New I/O) in Java?
Java NIO (java.nio) provides buffer-oriented, optionally non-blocking I/O.
| Classic I/O (java.io) | NIO (java.nio) | |
|---|---|---|
| Model | Stream-oriented | Buffer-oriented |
| Blocking | Always blocking | Can be non-blocking (Channels + Selectors) |
| File API | File class | Path, Paths, Files classes |
// NIO Path API
Path path = Paths.get("data.txt");
List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);
Files.write(path, "Hello".getBytes());
long size = Files.size(path);
Q72. What is memory-mapped file I/O?
Memory-mapped I/O (FileChannel.map()) maps a file directly into the JVM's virtual memory. The OS handles loading pages from disk on demand — extremely fast for large files since there's no explicit read/write call.
try (FileChannel fc = FileChannel.open(Paths.get("large.dat"), StandardOpenOption.READ)) {
MappedByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
byte firstByte = buffer.get(0); // direct memory access
}
Used in databases, log processors, and high-performance I/O scenarios.
12. Multithreading — Advanced
Q73. What is thread starvation?
Thread starvation occurs when a thread never gets CPU time because other higher-priority threads always preempt it, or a lock is always held by other threads.
Common causes:
- Threads with higher priority continuously executing
- A synchronized block held too long by one thread
- Unfair locking (threads don't get equal turns)
Solution: Use ReentrantLock with fairness = true:
Lock lock = new ReentrantLock(true); // fair lock — threads served in FIFO order
Q74. What is the difference between notify() and notifyAll()?
Both methods wake threads that are in wait() on the same object's monitor.
- notify() — wakes one arbitrary waiting thread (non-deterministic which one)
- notifyAll() — wakes all waiting threads; they compete for the lock
synchronized(obj) {
obj.notify(); // wake one
obj.notifyAll(); // wake all
}
Use notifyAll() by default — using notify() can lead to missed signals if the wrong thread is woken.
Q75. What is the difference between yield() and join()?
| yield() | join() | |
|---|---|---|
| Purpose | Hints the scheduler to give CPU to other threads of same/higher priority | Current thread waits for the specified thread to finish |
| Guarantee | No guarantee — scheduler may ignore the hint | Guaranteed — current thread blocks until target thread terminates |
| Called on | Thread.yield() — static, affects current thread | thread.join() — instance method |
Q76. What is the difference between synchronized method and synchronized block?
Synchronized method — locks the entire method on this (or the class object for static methods):
public synchronized void increment() { count++; } // locks 'this' for entire method
Synchronized block — locks only a specific section on a specified object:
public void increment() {
synchronized(this) { count++; } // locks only this block
// rest of method runs without lock
}
Prefer synchronized blocks — they have finer granularity, reducing contention and improving throughput.
13. Java 8 — Advanced Features
Q77. What is the purpose of Collectors in Java 8?
Collectors is a utility class providing built-in collector implementations for the collect() terminal operation:
List<String> names = Arrays.asList("Alice", "Bob", "Alice", "Charlie");
// Collect to List
List<String> list = names.stream().collect(Collectors.toList());
// Collect to Set (removes duplicates)
Set<String> set = names.stream().collect(Collectors.toSet());
// Join to String
String joined = names.stream().collect(Collectors.joining(", ")); // "Alice, Bob, Alice, Charlie"
// Group by length
Map<Integer, List<String>> byLength = names.stream()
.collect(Collectors.groupingBy(String::length));
// Count occurrences
Map<String, Long> counts = names.stream()
.collect(Collectors.groupingBy(s -> s, Collectors.counting()));
Q78. What is the difference between Predicate and Function?
| Predicate<T> | Function<T, R> | |
|---|---|---|
| Returns | boolean | Any type R |
| Method | test(T t) | apply(T t) |
| Used for | Filtering — stream.filter(predicate) | Transformation — stream.map(function) |
| Composing | and(), or(), negate() | andThen(), compose() |
Predicate<Integer> isEven = n -> n % 2 == 0;
Predicate<Integer> isPositive = n -> n > 0;
Predicate<Integer> isEvenAndPositive = isEven.and(isPositive);
Function<String, Integer> toLength = String::length;
Function<Integer, String> toStr = n -> "Length: " + n;
Function<String, String> composed = toLength.andThen(toStr);
System.out.println(composed.apply("hello")); // "Length: 5"
Q79. What are default methods in interfaces? Why were they introduced?
Default methods (Java 8+) are concrete methods in interfaces. They were introduced primarily for backward compatibility — adding new methods to existing interfaces without breaking all implementing classes.
interface Collection {
// New method added in Java 8 — all existing implementations inherit this
default void forEach(Consumer<? super E> action) {
for (E e : this) action.accept(e);
}
}
If two interfaces provide conflicting default methods, the implementing class must override and resolve the conflict:
interface A { default void greet() { System.out.println("A"); } }
interface B { default void greet() { System.out.println("B"); } }
class C implements A, B {
public void greet() { A.super.greet(); } // explicit resolution required
}
Q80. What is the new Date/Time API in Java 8?
The legacy java.util.Date and Calendar were mutable, not thread-safe, and poorly designed. Java 8 introduced java.time:
| Class | Purpose | Example |
|---|---|---|
| LocalDate | Date without time | LocalDate.now() → 2026-05-28 |
| LocalTime | Time without date | LocalTime.of(14, 30) |
| LocalDateTime | Date and time | LocalDateTime.now() |
| ZonedDateTime | Date and time with timezone | ZonedDateTime.now(ZoneId.of("Asia/Kolkata")) |
| Instant | Machine timestamp | Instant.now() |
| Duration / Period | Time/date spans | ChronoUnit.DAYS.between(d1, d2) |
All java.time classes are immutable and thread-safe.
14. Memory Management — Advanced
Q81. What causes memory leaks in Java?
Although Java has a GC, memory leaks can still occur when objects are unintentionally kept reachable:
- Static collections holding references to large objects that are never removed
- Listeners/callbacks not removed after use (common in GUI applications)
- ThreadLocal variables not cleaned up in thread pools
- Inner class instances holding a reference to the outer class
- Unclosed streams and connections (before Java 7's try-with-resources)
- String interning abuse — calling
.intern()on large/dynamic strings fills the pool
Detection tools: JVisualVM, Eclipse MAT (Memory Analyzer), JProfiler, -XX:+HeapDumpOnOutOfMemoryError
Q82. What is the difference between Minor GC and Major GC?
| Minor GC | Major (Full) GC | |
|---|---|---|
| Collects | Young Generation (Eden + Survivor) | Old Generation (and sometimes entire heap) |
| Frequency | Frequent | Infrequent |
| Pause time | Short (milliseconds) | Longer (may cause noticeable pauses) |
| Triggers | Eden space fills up | Old Gen fills up or explicit System.gc() |
Q83. What is System.gc()? Should you call it?
System.gc() is a hint to the JVM to run garbage collection. It does NOT guarantee that GC will run — the JVM may ignore it.
Should you call it? Almost never in production code:
- GC pauses block your application
- The JVM's GC algorithms are already well-tuned
- Calling it can actually hurt performance by triggering a Full GC unnecessarily
Legitimate use: in memory benchmarks or teardown of tests.
15. Servlets and Web Basics
Q84. What is a servlet?
A servlet is a Java class that handles HTTP requests and generates responses, running inside a servlet container (Tomcat, Jetty).
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse res)
throws IOException {
res.setContentType("text/html");
res.getWriter().println("<h1>Hello World</h1>");
}
}
Servlet lifecycle: init() → service() (called per request) → destroy()
Modern Java web development uses Spring MVC/Spring Boot which abstract servlets entirely.
Q85. What is the difference between forward and redirect in servlets?
| Forward (server-side) | Redirect (client-side) | |
|---|---|---|
| HTTP round trips | 1 — handled internally on server | 2 — server sends 302, client makes new request |
| URL in browser | Unchanged (original URL) | Changes to new URL |
| Request attributes | Shared — same HttpServletRequest | New request — attributes lost |
| Use when | Passing data to another page internally | After form submit (PRG pattern) to prevent re-submission |
Q86. What are cookies and sessions?
Cookie — a small piece of data stored on the client (browser). Sent with every HTTP request to the same domain. Used for preferences, authentication tokens.
Cookie cookie = new Cookie("username", "alice");
cookie.setMaxAge(86400); // 1 day
response.addCookie(cookie);
Session — server-side storage identified by a session ID (stored in a cookie named JSESSIONID). More secure since data stays on the server.
HttpSession session = request.getSession();
session.setAttribute("cart", cartObject);
Cart cart = (Cart) session.getAttribute("cart");
Difference: Cookies store data on the client; sessions store data on the server.
Q87. What is JDBC connection pooling?
A connection pool keeps a set of pre-opened database connections ready for reuse. Creating a new DB connection (~50-200ms) for every request is too expensive.
HikariCP (fastest, default in Spring Boot):
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
config.setUsername("root");
config.setPassword("pass");
config.setMaximumPoolSize(20);
config.setMinimumIdle(5);
DataSource ds = new HikariDataSource(config);
Pool lends a connection on getConnection() and returns it to the pool when conn.close() is called — the connection is NOT actually closed.
Q88. What is the difference between GET and POST?
| GET | POST | |
|---|---|---|
| Data in | URL query string (?name=Alice) | Request body |
| Security | Visible in URL/logs — not for sensitive data | Not in URL — more secure for passwords |
| Idempotent | Yes — repeated calls return same result | No — repeated submissions create duplicate records |
| Cacheable | Yes | No (by default) |
| Data size | Limited (~2KB URL limit) | No practical limit |
Q89. What is the MVC pattern?
Model-View-Controller (MVC) separates an application into three components:
- Model — business logic and data (POJO, database entities)
- View — presentation layer (JSP, Thymeleaf, React)
- Controller — handles user requests, coordinates Model and View (Servlet, Spring @Controller)
// Controller
@Controller
public class UserController {
@GetMapping("/users/{id}")
public String getUser(@PathVariable Long id, Model model) {
User user = userService.findById(id); // Model
model.addAttribute("user", user);
return "user-profile"; // View name
}
}
Benefits: Separation of concerns — changes to UI don't affect business logic and vice versa.
Q90. What are Java Beans?
A Java Bean is a plain Java class that follows a specific convention:
- Private fields
- Public no-arg constructor
- Public getters (
getXxx()) and setters (setXxx()) for each field - Implements
Serializable(optional but recommended)
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
public Person() {} // no-arg constructor required
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}
Java Beans are used heavily in JSP/EL, Spring (as beans managed by the IoC container), and JPA entities.
16. Collections — Advanced
Q91. What is the difference between HashSet and TreeSet?
| HashSet | TreeSet | |
|---|---|---|
| Internal structure | HashMap (hash table) | TreeMap (Red-Black Tree) |
| Ordering | No ordering guaranteed | Natural order (or Comparator) |
| Performance | O(1) add/remove/contains | O(log n) — tree traversal |
| Null elements | One null allowed | No null (comparison would throw NPE) |
| Use when | Fast lookup, no order needed | Sorted unique elements needed |
Q92. What is the load factor in HashMap?
The load factor determines when the HashMap resizes its internal array. Default is 0.75.
Resize threshold = capacity × loadFactor
Default: 16 × 0.75 = 12 → resize to 32 when 12 entries are added
Tradeoff:
- Lower load factor (e.g. 0.5) — fewer collisions, faster lookups, but more memory and more frequent resizes
- Higher load factor (e.g. 0.9) — less memory, but more collisions degrade to O(n) lookups
The default 0.75 is a good balance between time and space.
Q93. What is the difference between Vector and ArrayList?
| ArrayList | Vector | |
|---|---|---|
| Thread-safe | No | Yes (synchronized methods) |
| Performance | Faster (no synchronisation) | Slower |
| Growth | Grows by 50% when full | Doubles in size when full |
| Legacy | Java 1.2 (Collections Framework) | Java 1.0 (legacy) |
| Prefer instead | Default choice | Use Collections.synchronizedList() or CopyOnWriteArrayList |
Q94. How to make a collection read-only?
Use Collections.unmodifiableXxx() or List.of() / Map.of() (Java 9+):
// Unmodifiable wrapper (Java 1.2+)
List<String> mutable = new ArrayList<>(Arrays.asList("a","b","c"));
List<String> readonly = Collections.unmodifiableList(mutable);
readonly.add("d"); // UnsupportedOperationException
// Immutable factory (Java 9+)
List<String> immutable = List.of("a", "b", "c"); // cannot add/remove/set
Map<String, Integer> map = Map.of("one", 1, "two", 2);
Difference: unmodifiableList wraps the original — changes to the original are still visible. List.of() is truly immutable.
Q95. What is the difference between Iterator and ListIterator?
| Iterator | ListIterator | |
|---|---|---|
| Works with | Any Collection (List, Set) | List only |
| Direction | Forward only (next()) | Forward and backward (previous()) |
| Add elements | No | Yes — add() |
| Replace elements | No | Yes — set() |
| Get index | No | Yes — nextIndex(), previousIndex() |
Q96. What is PriorityQueue in Java?
PriorityQueue is a min-heap implementation — the smallest element is always at the head and dequeued first (natural ordering or Comparator).
PriorityQueue<Integer> pq = new PriorityQueue<>();
pq.add(30); pq.add(10); pq.add(20);
System.out.println(pq.poll()); // 10 — smallest first
// Max-heap (reverse order)
PriorityQueue<Integer> maxPq = new PriorityQueue<>(Comparator.reverseOrder());
maxPq.add(30); maxPq.add(10); maxPq.add(20);
System.out.println(maxPq.poll()); // 30 — largest first
Use cases: Dijkstra's algorithm, task scheduling by priority, merge K sorted lists.
17. OOP — Advanced
Q97. What is aggregation vs composition?
Both are "has-a" relationships, but differ in lifecycle dependency:
Aggregation — weak relationship; child can exist independently of parent:
class Department {}
class University {
List<Department> departments; // Department can exist without University
}
Composition — strong relationship; child's lifecycle is tied to parent:
class Room {}
class House {
private Room room = new Room(); // Room created with House, destroyed with House
}
Summary: Composition implies ownership; aggregation implies usage.
Q98. What is the Strategy pattern?
Strategy defines a family of algorithms, encapsulates each one, and makes them interchangeable at runtime.
interface SortStrategy {
void sort(int[] arr);
}
class BubbleSort implements SortStrategy {
public void sort(int[] arr) { /* bubble sort */ }
}
class QuickSort implements SortStrategy {
public void sort(int[] arr) { /* quick sort */ }
}
class Sorter {
private SortStrategy strategy;
Sorter(SortStrategy s) { this.strategy = s; }
void sort(int[] arr) { strategy.sort(arr); }
}
Sorter s = new Sorter(new QuickSort());
s.sort(data); // easily swap strategy without changing Sorter
Q99. What is the Decorator pattern?
Decorator adds behaviour to objects dynamically without subclassing — wraps the original object.
interface Coffee { double getCost(); String getDescription(); }
class SimpleCoffee implements Coffee {
public double getCost() { return 1.0; }
public String getDescription() { return "Coffee"; }
}
class MilkDecorator implements Coffee {
private Coffee coffee;
MilkDecorator(Coffee c) { this.coffee = c; }
public double getCost() { return coffee.getCost() + 0.25; }
public String getDescription() { return coffee.getDescription() + ", Milk"; }
}
Coffee c = new MilkDecorator(new SimpleCoffee());
System.out.println(c.getDescription()); // "Coffee, Milk"
System.out.println(c.getCost()); // 1.25
Java's own BufferedReader wrapping FileReader is the classic decorator example.
Q100. What is the difference between static method and instance method?
| Static method | Instance method | |
|---|---|---|
| Belongs to | Class | Object (instance) |
| Access instance fields? | No | Yes |
| Call with | ClassName.method() | object.method() |
| Overriding | Cannot be overridden (only hidden) | Can be overridden in subclass |
| Use for | Utility/helper methods (Math.sqrt, Collections.sort) | Operations on object state |
18. Java Keywords and Misc
Q101. What is the difference between break and continue?
- break — exits the loop or switch immediately; control passes to the statement after the loop
- continue — skips the rest of the current iteration and moves to the next iteration
for (int i = 0; i < 10; i++) {
if (i == 5) break; // exits loop at i=5 → prints 0,1,2,3,4
System.out.println(i);
}
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) continue; // skip even → prints 1,3,5,7,9
System.out.println(i);
}
Both can be used with a label to break/continue an outer loop:
outer:
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (j == 1) break outer; // exits both loops
}
}
Q102. What is instanceof vs isInstance()?
| instanceof | Class.isInstance() | |
|---|---|---|
| Type | Operator (keyword) | Method on Class object |
| Usage | obj instanceof ClassName | clazz.isInstance(obj) |
| Dynamic class? | No — class must be known at compile time | Yes — can use any Class object at runtime |
| Use case | Typical runtime type check | Reflection — checking against dynamically loaded classes |
Object obj = "hello";
System.out.println(obj instanceof String); // true
Class<?> clazz = Class.forName("java.lang.String");
System.out.println(clazz.isInstance(obj)); // true — useful in reflection
Q103. What is the difference between import and static import?
- import — imports a class or package so you can use the class name without the full qualified name
- static import — imports static members (fields/methods) directly, so you can use them without the class name
import java.util.List; // import class
import static java.lang.Math.PI; // static import
import static java.lang.Math.sqrt; // static import
double circumference = 2 * PI * r; // no need for Math.PI
double root = sqrt(16); // no need for Math.sqrt
Caution: Overusing static imports reduces readability by hiding where methods come from.
Q104. What is the difference between System.out.println() and System.err.println()?
- System.out — standard output stream; used for normal program output
- System.err — standard error stream; used for error messages and diagnostics
Both print to the console by default but they are separate streams. IDEs typically display System.err output in red. You can redirect them independently in shell:
java MyApp 1>output.txt 2>errors.txt
Q105. What is the ClassLoader in Java?
ClassLoaders load class files from the filesystem or network into the JVM at runtime.
ClassLoader hierarchy (parent-delegation model):
- Bootstrap ClassLoader — loads core JDK classes (java.lang, java.util) from rt.jar/modules
- Platform (Extension) ClassLoader — loads from
$JAVA_HOME/lib/ext - Application ClassLoader — loads from CLASSPATH (your application classes)
When loading a class, each loader delegates to its parent first. Only if the parent can't find it does the child try. This prevents user-defined java.lang.String from overriding the JDK's version.
ClassLoader cl = Thread.currentThread().getContextClassLoader();
System.out.println(cl); // sun.misc.Launcher$AppClassLoader
System.out.println(cl.getParent()); // sun.misc.Launcher$ExtClassLoader
System.out.println(cl.getParent().getParent()); // null (Bootstrap is native)
Q106. What is the Proxy class in Java?
java.lang.reflect.Proxy creates dynamic proxy classes at runtime that implement one or more interfaces, delegating all method calls to an InvocationHandler.
interface Greeter { void greet(String name); }
Greeter proxy = (Greeter) Proxy.newProxyInstance(
Greeter.class.getClassLoader(),
new Class[]{Greeter.class},
(proxyObj, method, args) -> {
System.out.println("Before: " + method.getName());
// could delegate to real implementation here
System.out.println("Hello, " + args[0]);
return null;
}
);
proxy.greet("Alice"); // "Before: greet" then "Hello, Alice"
Dynamic proxies power Spring AOP, JDK-based transaction management, and mock frameworks like Mockito.
Q107. What is the assert keyword in Java?
assert is used for debugging and testing invariants — conditions that should always be true at a given point. If the condition is false, an AssertionError is thrown.
int age = -1;
assert age >= 0 : "Age cannot be negative: " + age;
Assertions are disabled by default at runtime. Enable with JVM flag -ea (enable assertions):
java -ea MyApp
Use assertions for internal invariants, not for input validation from external callers (use IllegalArgumentException for that).
Q108. What is the difference between Error and Exception?
| Error | Exception | |
|---|---|---|
| Caused by | JVM/system-level problems | Application-level problems |
| Should catch? | No — indicates a fatal condition | Yes — can be handled and recovered |
| Examples | OutOfMemoryError, StackOverflowError, VirtualMachineError | IOException, NullPointerException, IllegalArgumentException |
| Recovery | Generally not recoverable | Often recoverable with proper handling |
Q109. What is tight coupling vs loose coupling?
Tight coupling — classes depend directly on concrete implementations:
class OrderService {
private MySQLDatabase db = new MySQLDatabase(); // tightly coupled
}
Loose coupling — classes depend on interfaces/abstractions:
class OrderService {
private Database db; // depends on interface
OrderService(Database db) { this.db = db; } // injected from outside
}
Loose coupling is achieved via Dependency Injection, interfaces, and the Factory/Strategy patterns. It makes code easier to test, maintain, and swap implementations.
Q110. What is the difference between abstract class and concrete class?
- Abstract class — cannot be instantiated; may have abstract methods that subclasses must implement. Defined with the
abstractkeyword. - Concrete class — a fully implemented class that can be instantiated with
new.
abstract class Vehicle {
abstract void startEngine(); // must be implemented
void stop() { System.out.println("Stopped"); } // concrete
}
class Car extends Vehicle {
void startEngine() { System.out.println("Car engine started"); }
}
Vehicle v = new Car(); // OK — Car is concrete
Vehicle x = new Vehicle(); // COMPILE ERROR — abstract class
Q111. What is autoboxing pitfall with null?
Unboxing a null wrapper causes NullPointerException:
Integer i = null;
int x = i; // NullPointerException — unboxing null
Always check for null before unboxing:
int x = (i != null) ? i : 0;
Also beware of performance: autoboxing in tight loops creates many short-lived objects:
Long sum = 0L;
for (long i = 0; i < 1_000_000; i++) {
sum += i; // autoboxes i → Long on every iteration!
}
// Use: long sum = 0L; instead
Q112. What is the purpose of the forEach() method in Iterable?
forEach(Consumer<T> action) was added in Java 8 to Iterable as a default method. It iterates over each element and passes it to the Consumer:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// Traditional
for (String name : names) { System.out.println(name); }
// forEach with lambda
names.forEach(name -> System.out.println(name));
// forEach with method reference (most concise)
names.forEach(System.out::println);
Available on all Collections, and on Map via Map.forEach((k,v) -> ...).
Q113. What is String.valueOf() vs toString()?
| String.valueOf(obj) | obj.toString() | |
|---|---|---|
| Null safe | Yes — returns "null" string | No — throws NullPointerException if obj is null |
| Usage | Static method on String class | Instance method on every Object |
| Prefer when | Object might be null | Object is guaranteed non-null |
Q114. What are the primitive data types in Java?
Java has 8 primitive types:
| Type | Size | Range | Default |
|---|---|---|---|
| byte | 1 byte | -128 to 127 | 0 |
| short | 2 bytes | -32,768 to 32,767 | 0 |
| int | 4 bytes | -2^31 to 2^31-1 | 0 |
| long | 8 bytes | -2^63 to 2^63-1 | 0L |
| float | 4 bytes | ~±3.4 x 10^38 (7 digits) | 0.0f |
| double | 8 bytes | ~±1.8 x 10^308 (15 digits) | 0.0d |
| char | 2 bytes | 0 to 65,535 (Unicode) | ' |