60+ Java Interview Questions and Answers You Must Know (Updated 2026)

Last updated by Vartika Rai on Mar 27, 2026 at 12:10 PM
| Reading Time: 3 minute

Article written by Rishabh Dev Choudhary, under the guidance of Marcelo Lotif Araujo, a Senior Software Developer and an AI Engineer. Reviewed by Mrudang Vora, an Engineering Leader with 15+ years of experience.

| Reading Time: 3 minutes

Java interview questions remain one of the most searched topics among developers preparing for technical rounds, and for good reason. Java powers enterprise backends at companies like Google, Amazon, and Netflix, and continues to dominate software engineering interviews in 2026.

Whether you are a fresher covering OOP and JVM basics or an experienced engineer brushing up on concurrency and Java 8+ features, this guide covers the full spectrum of Java interview questions and answers from foundational concepts to the advanced topics that distinguish mid-level from senior candidates. You will find comparison tables, code snippets, and interview-specific callouts throughout.

For a deeper dive into one of Java’s most tested areas, explore these that frequently come up in senior interviews.

Key Takeaways

  • Java remains one of the most in-demand languages in enterprise software, and this guide walks through the full spectrum of interview topics, from JVM architecture and memory management all the way through collections, multithreading, Java 8+ features, and design patterns, covering what freshers and experienced engineers alike need to know.
  • A recurring theme across the guide is that Java interviews test reasoning, not memorization, understanding why Strings are immutable, why volatile does not guarantee atomicity, or why ConcurrentHashMap beats Hashtable will always outperform a candidate who can only recite definitions.
  • The Collections and multithreading sections are where mid-level candidates most often differentiate themselves, and the guide covers the specific trade-offs interviewers probe, ArrayList vs LinkedList access patterns, fail-fast vs fail-safe iterators, synchronized vs volatile, and thread pool sizing strategies.
  • Modern Java features including Lambdas, Streams, Records, and Sealed Classes are increasingly tested even at non-senior levels, and the guide treats them as first-class topics rather than footnotes, because interviewers in 2026 expect fluency in Java 8+ to be a baseline, not a bonus.
  • The guide closes with a practical preparation roadmap that sequences topics in the order they build on each other, starting with core fundamentals and working up through design patterns and JVM internals, so you can use it as a study plan, not just a reference.

Core Java Interview Questions

These core Java interview questions test the fundamentals every interviewer expects you to know, from JDK architecture to memory management and language design choices.

Q1. What is the difference between JDK, JRE, and JVM?

These three components are nested, JDK wraps JRE, which wraps JVM. Each layer adds a different layer of capability.

Component What It Contains Purpose
Java Virtual Machine (JVM) Bytecode interpreter, JIT compiler, garbage collector, runtime memory areas Executes compiled Java bytecode on any platform
Java Runtime Environment(JRE) JVM + standard class libraries (java.lang, java.util, etc.) Provides the minimum environment needed to run Java applications
Java Development Kit (JDK) JRE + compiler (javac), debugger (jdb), profiler, javadoc, and other dev tools Complete toolkit for developing, compiling, and running Java programs

Nesting relationship (outer to inner):

JDK ⊃ JRE ⊃ JVM

When you install the JDK, you get everything. End users who only run Java programs need the JRE. The JVM itself is what makes Java platform-independent; it translates bytecode into native machine instructions at runtime.

Q2. What is a JIT Compiler?

The JIT (Just-In-Time) compiler is a component of the JVM that improves runtime performance by compiling frequently executed bytecode into native machine code during program execution, rather than interpreting it line by line each time.

Execution flow:

Java Source (.java) → javac → Bytecode (.class) → JVM/JIT → Native Machine Code

The JVM initially interprets bytecode, then identifies ‘hot spots’ (frequently called methods) and compiles them to native code for subsequent calls. This is why Java programs often speed up during warm-up; the JIT is optimizing hot paths in the background.

Q3. Explain the difference between equals() and == in Java.

Feature == Operator .equals() Method
Compares References (memory addresses) Content / logical value
Works on Primitives and object references Objects only
Default behavior (Object) Reference equality Reference equality (until overridden)
String behavior True only if same pool object True if character sequences match
Null safety Safe , null == null is true Throws NullPointerException if called on null

The key distinction is that == checks whether two variables point to the exact same memory location, while .equals() checks whether the contents are logically equivalent. This difference matters most with Strings, two new String(“hello”) calls produce objects with identical content but different memory addresses, so == returns false while .equals() returns true.

String a = new String("hello");
String b = new String("hello");
String c = "hello";
String d = "hello";



System.out.println(a == b);      
// false - different heap objects

System.out.println(a.equals(b));   
// true - same character content

System.out.println(c == d);        
// true - same String pool reference

System.out.println(c.equals(d));   
// true - same content

💡 Interview Trap: What happens with == on Integer objects above 127? Java caches Integer values from -128 to 127. Integers in that range share a cached instance, so == returns true. Above 127, new objects are created, so == returns false. Many candidates do not know where the cache boundary is.

Q4. Why is the Java platform independent?

Java achieves platform independence through a two-step compilation model. The Java compiler (javac) does not compile source code to native machine code; it compiles to an intermediate format called bytecode (.class files). Bytecode is platform-neutral and is only converted to native instructions at runtime by the JVM installed on the target machine.

Flow: Java Source → javac → Bytecode → JVM (Windows / Linux / macOS) → Native Code

This is the foundation of Java’s ‘Write Once, Run Anywhere’ (WORA) guarantee that the same .class file runs on any platform that has a compatible JVM, without recompilation.

Q5. Why is Java not completely object-oriented?

Java is not purely object-oriented because it supports eight primitive types, int, long, short, byte, float, double, char, and boolean, that are not objects. They are stored directly on the stack as raw values, not as object references on the heap.

// Primitives - not objects, stored on the stack
int age     = 25;
boolean active = true;
char grade  = 'A';


// Wrapper classes - object equivalents, stored on the heap
Integer ageObj    = Integer.valueOf(25);
Boolean activeObj = Boolean.TRUE;
Character gradeObj = Character.valueOf('A');

Java provides autoboxing to convert between primitives and their wrapper class equivalents automatically, but the underlying distinction remains. A purely object-oriented language (like Smalltalk or Ruby) has no primitives at all.

Q6. What is the difference between Stack and Heap memory in Java?

Feature Stack Memory Heap Memory
Stores Local variables, method call frames, object references All objects and instance variables
Access speed Very fast (LIFO structure) Slower (dynamic allocation, GC overhead)
Size Small and fixed per thread Large and configurable (-Xmx flag)
Thread safety Thread-local; each thread has its own stack Shared across all threads; needs synchronization
Lifecycle Freed automatically when the method returns Managed by Garbage Collector
Error on overflow StackOverflowError (e.g., infinite recursion) OutOfMemoryError

Stack and Heap serve entirely different roles in Java’s memory model. The stack is fast, thread-private, and self-managing. It automatically grows and shrinks with method calls and returns. The heap is where all objects live and is shared across threads, which is why concurrent access requires synchronization. Knowing this distinction helps explain why thread safety issues occur and why infinite recursion produces a StackOverflowError.

void createPerson() {
    // 'p' (the reference) lives on the STACK
    // The actual Person object lives on the HEAP
    Person p = new Person("Alice");
}

// When createPerson() returns, 'p' is popped off the stack.
// The Person object on the heap waits for GC.

Practical rule: when you call new Object(), the reference variable goes on the stack and the object itself goes on the heap. Primitives declared inside a method go on the stack directly.

Q7. What is Data Encapsulation?

Encapsulation is the OOP principle of hiding an object’s internal state and requiring all interaction to go through a defined public interface. It is implemented in Java by declaring fields private and providing public getter and setter methods.

public class BankAccount {
    private double balance;   // hidden - not directly accessible

    

    public double getBalance() {
        return balance;
    }

    

    public void deposit(double amount) {
        if (amount > 0) balance += amount;  // validation enforced here
    }

    

    public void withdraw(double amount) {
        if (amount > 0 && amount <= balance) balance -= amount;
    }
}

The balance cannot be changed directly from outside; all modifications must go through deposit() or withdraw(), which enforces business rules. This is the core benefit of encapsulation: controlled, validated access to internal state.

Q8. Why is char[] preferred over String for storing passwords?

Strings in Java are immutable and interned in the String pool. A password stored as a String remains in memory until the garbage collector removes it, which could be long after you are done using it. During that window, a memory dump or heap inspection could expose it in plaintext.

A char[] can be explicitly zeroed out as soon as the password is no longer needed:

// RISKY - password lingers in String pool, cannot be cleared
String password = "secret123";


// SAFER - char array can be wiped immediately after use
char[] password = {'s','e','c','r','e','t','1','2','3'};
// ... use password ...
Arrays.fill(password, '�');   // overwrite with null chars

Q9. What happens if the main() method is not static?

If main() is not declared static, the JVM cannot call it without first creating an instance of the class, but it has no way of knowing how to construct that instance (which constructor arguments to use, etc.). The program will compile but throw a runtime error.

public class Demo {
    // Missing 'static' - compiles fine, fails at runtime
    public void main(String[] args) {
        System.out.println("Will not run");
    }
}

// Runtime output:
// Error: Main method is not static in class Demo, please define the main method as:
//    public static void main(String[] args)

The JVM entry point contract requires: public (accessible), static (callable without an instance), void (no return value), named main, with a String[] parameter.

Q10. Does the finally block execute after System.exit(0)?

No, System.exit(0) terminates the JVM immediately. Any finally block that would normally execute after a try or catch block is bypassed entirely because the JVM process itself is shut down before execution can reach it.

public class FinallyTest {
    public static void main(String[] args) {
        try {
            System.out.println("In try");
            System.exit(0);
        } finally {
            System.out.println("In finally"); // NEVER prints
        }
    }
}

// Output: In try

By contrast, a return statement inside a try block does allow the finally block to execute before the method returns. System.exit() is unique in bypassing finally because it kills the JVM process outright.

Q11. Why are Strings Immutable in Java?

String immutability is a deliberate design decision in Java, justified by four separate benefits. Interviewers expect you to know at least three:

  • String pool optimization: Because Strings cannot change, the JVM safely allows multiple references to share the same String object in the pool, saving memory significantly.
  • Security: Class names loaded by the ClassLoader are Strings. If they were mutable, malicious code could alter a class name after a security check passes, bypassing it.
  • Thread safety: Immutable objects are inherently safe to share across threads; no synchronization is needed for String objects.
  • Hashcode caching: String.hashCode() is computed once and cached. Since the content can never change, the cached value is always valid, enabling efficient use as HashMap keys.
String s = "hello";
s.concat(" world");        // Does NOT modify s
System.out.println(s);     // Prints: hello



String s2 = s.concat(" world");  // Creates a NEW String object
System.out.println(s2);          // Prints: hello world

💡 Follow-up trap: ‘How do you create a mutable string?’ Answer: StringBuilder (single-threaded, faster) or StringBuffer (thread-safe, synchronized). Never use String concatenation in a loop; it creates a new object each iteration.

Q12. What is the Difference Between String, StringBuilder, and StringBuffer?

String handling is one of the most tested areas in Java interviews, from immutability and the String pool to common manipulation methods. For a focused set of questions on this topic, explore Java String interview questions covering pool behaviour, comparison traps, and StringBuilder vs StringBuffer trade-offs.

Feature String StringBuilder StringBuffer
Mutability Immutable; every change creates a new object Mutable, modifies in place Mutable, modifies in place
Thread safety Inherently thread-safe (immutable) Not thread-safe Thread-safe (synchronized methods)
Performance Slow in loops (new object each concat) Fastest for single-threaded use Slower than StringBuilder due to synchronization
Use case Constant strings, map keys, config values String building in loops or single-threaded code String building in multi-threaded environments

The three classes form a spectrum of trade-offs between mutability, thread safety, and speed. String is best for values that never change. StringBuilder is the go-to for building strings in single-threaded code, especially in loops, since it mutates one object rather than creating many. StringBuffer adds synchronized methods for thread safety but pays a performance cost in modern multi-threaded code, better concurrency designs often make StringBuffer unnecessary.

// String in a loop - creates 1000 objects (BAD for performance)
String result = "";
for (int i = 0; i < 1000; i++) result += i;



// StringBuilder in a loop - modifies one object (GOOD)
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) sb.append(i);
String result = sb.toString();

Java Coding Interview Questions and Answers

These hands-on Java coding interview questions test your ability to write clean, efficient code – expect these in technical phone screens and onsite coding rounds.

Q13. How to reverse a String in Java?

// Approach 1: StringBuilder.reverse() - clean and readable
public static String reverseString(String s) {
    return new StringBuilder(s).reverse().toString();
}



// Approach 2: Manual char array swap - common in interviews
public static String reverseManual(String s) {
    char[] chars = s.toCharArray();
    int left = 0, right = chars.length - 1;
    while (left < right) {
        char temp = chars[left];
        chars[left++] = chars[right];
        chars[right--] = temp;
    }
    return new String(chars);
}

Both approaches are O(n) time and O(n) space. The StringBuilder approach is preferred for production code. The manual approach demonstrates understanding of two-pointer technique, useful to mention in interviews.

Q14. How to generate the Fibonacci series using recursion?

// Recursive approach
public static int fibonacci(int n) {
    if (n <= 1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
}



// Iterative approach - always mention this alternative
public static int fibIterative(int n) {
    if (n <= 1) return n;
    int a = 0, b = 1;
    for (int i = 2; i <= n; i++) {
        int temp = a + b;
        a = b;
        b = temp;
    }
    return b;
}

The recursive version is elegant but expensive. It recalculates the same sub-problems repeatedly, leading to O(2^n) time complexity. The iterative version keeps track of only two previous values, reducing this to O(n) time and O(1) space. In interviews, writing the recursive solution first and then proactively offering the iterative or memoized alternative demonstrates strong algorithmic awareness and performance thinking.

Time complexity: Recursive = O(2^n), exponential, impractical for large n. Iterative = O(n) time, O(1) space.

💡 Always mention the iterative alternative in interviews; it signals you understand the performance trade-off. For production use, memoization (top-down DP) or the iterative approach should replace naive recursion.

Q15. How to remove leading and trailing whitespaces from a String?

String raw = "   hello world   ";



// Java 1.0+: trim() - removes ASCII whitespace only (t, n, r, space)
System.out.println(raw.trim());    // "hello world"



// Java 11+: strip() - Unicode-aware, handles all whitespace characters
System.out.println(raw.strip());         // "hello world"
System.out.println(raw.stripLeading());  // "hello world   "
System.out.println(raw.stripTrailing()); // "   hello world"

strip() is preferred in modern Java (11+) because it uses Character.isWhitespace() which handles Unicode whitespace characters that trim() would miss. For codebases on Java 8 or below, trim() remains the standard.

Q16. How to create a deadlock scenario in Java?

A deadlock occurs when Thread A holds Lock 1 and waits for Lock 2, while Thread B holds Lock 2 and waits for Lock 1, creating a circular wait that never resolves.

public class DeadlockDemo {

    static final Object lock1 = new Object();
    static final Object lock2 = new Object();


    public static void main(String[] args) {

        Thread t1 = new Thread(() -> {
            synchronized (lock1) {
                System.out.println("T1 acquired lock1, waiting for lock2");
                try { Thread.sleep(50); }
                catch (InterruptedException e) {}

                synchronized (lock2) {   
                    // waits - T2 holds lock2
                    System.out.println("T1 acquired both locks");
                }
            }
        });


        Thread t2 = new Thread(() -> {
            synchronized (lock2) {
                System.out.println("T2 acquired lock2, waiting for lock1");

                synchronized (lock1) {   
                    // waits - T1 holds lock1
                    System.out.println("T2 acquired both locks");
                }
            }
        });


        t1.start();
        t2.start();

        // Both threads block forever - deadlock
    }
}

Prevention: always acquire multiple locks in the same fixed order across all threads. If T1 and T2 both acquired lock1 before lock2, the circular wait cannot form.

Q17. How to implement Binary Search in Java?

// Iterative binary search - O(log n) time, O(1) space
public static int binarySearch(int[] arr, int target) {

    int left = 0, right = arr.length - 1;

    while (left <= right) {

        int mid = left + (right - left) / 2;  
        // avoids integer overflow

        if (arr[mid] == target)  
            return mid;

        else if (arr[mid] < target)  
            left = mid + 1;

        else  
            right = mid - 1;
    }

    return -1;  
    // not found
}

Time complexity: O(log n), each iteration halves the search space.

Important: The array must be sorted before binary search can be applied. Note that mid = left + (right – left) / 2 avoids integer overflow that mid = (left + right) / 2 can cause on very large arrays.

Q18. How to check if two arrays contain the same elements?

import java.util.Arrays;

public static boolean sameElements(int[] a, int[] b) {

    if (a.length != b.length) 
        return false;

    Arrays.sort(a);
    Arrays.sort(b);

    return Arrays.equals(a, b);
}



// Example:
int[] arr1 = {3, 1, 2};
int[] arr2 = {2, 3, 1};

System.out.println(sameElements(arr1, arr2));  
// true

Sorting both arrays brings them to the same canonical order, then Arrays.equals() compares element by element.

Time complexity: O(n log n) for sorting. Alternative: use a frequency map (HashMap) for O(n) time if the sort-then-compare approach is not acceptable.

Q19. How to format a date in Java?

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;



// Java 8+ (preferred): DateTimeFormatter - immutable and thread-safe
LocalDate date = LocalDate.now();

DateTimeFormatter formatter =
    DateTimeFormatter.ofPattern("dd-MM-yyyy");

System.out.println(date.format(formatter));
// e.g., "15-03-2026"



// Legacy (pre-Java 8): SimpleDateFormat - NOT thread-safe
import java.text.SimpleDateFormat;
import java.util.Date;

SimpleDateFormat sdf =
    new SimpleDateFormat("dd-MM-yyyy");

System.out.println(sdf.format(new Date()));

Prefer DateTimeFormatter from the java.time package (Java 8+), it is immutable and thread-safe. SimpleDateFormat is a known source of concurrency bugs and should be avoided in new code.

Q20. How to use the forEach() method in Java?

import java.util.List;
import java.util.Map;

List<String> names =
    List.of("Alice", "Bob", "Carol");

// forEach with lambda
names.forEach(name -> 
    System.out.println(name)
);

// forEach with method reference (more concise)
names.forEach(System.out::println);

// Map.forEach with key and value
Map<String, Integer> scores =
    Map.of("Alice", 95, "Bob", 87);

scores.forEach((name, score) ->
    System.out.println(name + ": " + score)
);

forEach() is defined on the Iterable interface and on Map. It accepts a Consumer<T> functional interface typically supplied as a lambda or method reference. It is part of Java 8’s internal iteration model and works seamlessly with Streams.

Q21. How to create a record in Java?

// Java 14+ feature (stable in Java 16+)
public record Point(int x, int y) { }


// The compiler auto-generates:
// - Canonical constructor: Point(int x, int y)
// - Accessor methods:      p.x(), p.y()
// - equals(), hashCode(), toString()



Point p1 = new Point(3, 4);
Point p2 = new Point(3, 4);

System.out.println(p1);
// Point[x=3, y=4]

System.out.println(p1.equals(p2));
// true

System.out.println(p1.x());
// 3

⚠️ Pro Tip: Records are a Java 14+ feature (stable from Java 16). Always mention the version in interviews; interviewers test version awareness. Records are implicitly final and cannot extend other classes, though they can implement interfaces.

Core Java Concepts Interview Questions

These questions probe your understanding of Java internals, classloaders, constructors, and object mechanics.

Q22. What is a ClassLoader?

A ClassLoader is responsible for loading Java class files into the JVM at runtime. Java uses a delegation hierarchy with three built-in classloaders:

Bootstrap ClassLoader → Extension ClassLoader → Application ClassLoader

  • Bootstrap ClassLoader: The root loader (written in native code). Loads core Java classes from rt.jar (java.lang, java.util, etc.)
  • Extension ClassLoader: Loads classes from the JRE’s ext/ directory (javax.* packages and JVM extensions)
  • Application ClassLoader: Loads classes from your application’s classpath, your code, and third-party JARs
  • The delegation model: when a class needs to be loaded, the Application ClassLoader asks the Extension ClassLoader first, which asks Bootstrap first. Only if the parent cannot find the class does the child attempt to load it, this prevents application classes from overriding core Java classes.

Q23. What are the differences between constructors and methods?

Feature Constructor Method
Name Must match the class name exactly Any valid identifier
Return type None; not even a void Must declare a return type (or void)
Invocation Called automatically by the new keyword Called explicitly on an object
Inheritance Not inherited by subclasses Inherited (unless private or static)
Purpose Initialize object state at creation Define object behaviour/operations

If you do not define any constructor, Java provides a default no-argument constructor. If you define any constructor with parameters, the default is no longer generated automatically.

Q24. What are the restrictions of static methods in Java?

The following are the restrictions of using static methods in Java:

  • Cannot access instance variables or instance methods directly; there is no object context to refer to
  • Cannot use the this keyword, this refers to the current instance, which does not exist in a static context
  • Cannot be overridden, static methods belong to the class, not the object; they can be hidden in a subclass but not overridden (method hiding, not polymorphism)
  • Cannot be abstract, static methods must have a body in the class where they are defined
public class Counter {

    private int count = 0;       
    // instance variable

    private static int total = 0; 
    // class variable



    public static void showTotal() {

        System.out.println(total);  
        // OK - static variable

        // System.out.println(count);
        // COMPILE ERROR - instance variable

        // this.count++;
        // COMPILE ERROR - 'this' not available
    }
}

Q25. What is the purpose of the this keyword?

The this keyword refers to the current object instance. It has three main uses in Java:

public class Person {

    private String name;
    private int age;



    // Use 1: disambiguate field from parameter with same name
    public Person(String name, int age) {
        this.name = name;
        // 'this.name' = field; 'name' = parameter

        this.age = age;
    }



    // Use 2: constructor chaining - call another constructor in same class
    public Person(String name) {
        this(name, 0);
        // calls Person(String, int)
    }



    // Use 3: pass current object as an argument
    public void register(Registry r) {
        r.add(this);
    }
}

Q26. What is constructor chaining?

Constructor chaining is the practice of calling one constructor from another to avoid duplicating initialization logic. In Java it is done using this() (same class) or super() (parent class).

public class Vehicle {

    String type;
    int speed;



    Vehicle(String type, int speed) {
        this.type  = type;
        this.speed = speed;
    }
}



public class Car extends Vehicle {

    int doors;



    Car(int doors) {
        this(doors, 120);
        // chains to Car(int, int)
    }



    Car(int doors, int speed) {

        super("Car", speed);
        // calls Vehicle(String, int)

        this.doors = doors;
    }
}

this() or super() must be the first statement in a constructor. This means only one chained call is allowed per constructor.

Q27. What is the difference between this and super?

Feature this super
Refers to Current class instance Immediate parent class instance
Constructor call this() invokes another constructor in the same class super() invokes the parent class constructor
Method call this.method() calls current class method super.method() calls overridden parent method
Variable access this.field disambiguates from local variable super.field accesses hidden parent field
Position in constructor Must be first statement Must be first statement

this and super both serve as references within a class, but they point in different directions of the inheritance hierarchy. this always refers to the current object, while super provides a window into the parent class, essential when a subclass overrides a method but still needs to invoke the parent’s implementation. Their constructor-call forms (this() and super()) are mutually exclusive in any single constructor since both must be the first statement.

Q28. What is Object Cloning?

Object cloning creates a copy of an existing object. In Java, the Object class provides a protected clone() method. To use it, a class must implement the Cloneable marker interface, otherwise clone() throws CloneNotSupportedException.

public class Employee implements Cloneable {

    String name;
    int[] scores;  
    // reference type



    @Override
    public Employee clone() throws CloneNotSupportedException {

        return (Employee) super.clone();  
        // SHALLOW copy

    }
}



// Shallow copy: 'name' is copied, but 'scores' array is SHARED
// Deep copy: you must manually clone the array too

public Employee deepClone() throws CloneNotSupportedException {

    Employee copy = (Employee) super.clone();

    copy.scores = scores.clone();  
    // clone the array separately

    return copy;
}

Shallow copy: Primitive fields are copied by value; reference fields share the same underlying object.

Deep copy: All nested objects are also cloned, and both copies are fully independent.

Q29. What is Aggregation in Java?

Aggregation is a HAS-A relationship where one class contains a reference to another, but both objects have independent lifecycles, the contained object can exist without the container.

// Department HAS-A list of Employees
// Employees can exist independently of the Department

public class Department {

    private String name;

    private List<Employee> employees;  
    // aggregation



    public Department(String name, List<Employee> employees) {

        this.name      = name;
        this.employees = employees;
    }
}



// If Department is deleted, Employee objects continue to exist

Aggregation differs from Composition: in Composition, the child object cannot exist independently (e.g., a House and its Rooms, if the House is destroyed, the Rooms cease to exist). In Aggregation, the contained object’s lifecycle is independent.

OOP and Abstract Concepts in Java

OOP questions reveal how you think about code architecture, expect these in every Java interview.

Q30. What is the difference between an abstract class and an interface?

Feature Abstract Class Interface
Methods Can have abstract AND concrete methods Abstract by default; Java 8+ allows default and static methods; Java 9+ allows private methods
Constructors Yes, called via super() from subclass No constructors
Multiple inheritance No, a class can extend only one abstract class Yes, a class can implement multiple interfaces
State (fields) Can have instance variables Only public static final constants
Access modifiers Any modifier on members Members are public by default
When to use Shared base implementation + partial contracts Pure contracts, cross-type capability grants

The practical rule of thumb is: use an abstract class when classes share state or behavior (IS-A relationship), and use an interface when you want to define a capability that unrelated classes can share (CAN-DO relationship). Note that Java 8 and 9 have blurred this distinction somewhat by adding default, static, and private methods to interfaces; a critical point interviewers specifically test to see if your knowledge is up to date.

// Abstract class with shared state and behaviour
public abstract class Animal {

    protected String name;

    public void breathe() {
        System.out.println("Breathing");
    } 
    // concrete method

    public abstract void speak();  
    // must be implemented
}



// Interface - pure contract, Java 8+ allows defaults
public interface Flyable {

    void fly();  
    // abstract by default

    default void land() {
        System.out.println("Landing");
    } 
    // default method
}

💡 Interviewers love asking: ‘Has the difference changed in modern Java?’ Yes, Java 8 added default and static methods to interfaces; Java 9 added private methods. The line has blurred, but abstract classes still win when you need shared mutable state.

Q31. Can abstract classes have constructors?

Yes, abstract classes can have constructors, even though you cannot instantiate an abstract class directly. The constructor exists to be called by subclass constructors via super(), allowing the abstract class to initialize its own fields.

public abstract class Shape {

    protected String color;



    public Shape(String color) {  
        // constructor in abstract class

        this.color = color;
    }



    public abstract double area();
}



public class Circle extends Shape {

    private double radius;



    public Circle(String color, double radius) {

        super(color);  
        // calls abstract class constructor

        this.radius = radius;
    }



    public double area() {
        return Math.PI * radius * radius;
    }
}

Q32. When should you prefer an abstract class over an interface?

Prefer Abstract Class When… Prefer Interface When…
Multiple related classes share state (instance variables) You want to define a capability that unrelated classes can share
You have common method implementations to share (reduce code duplication) Multiple inheritance of type is needed (implement multiple interfaces)
You need non-public methods (protected, package-private) You want to define a pure contract with no shared state
The relationship is IS-A (Dog is an Animal) The relationship is CAN-DO (Bird can Fly, Plane can Fly)

The IS-A vs CAN-DO distinction is the most reliable heuristic for this decision. An abstract class models a family of related things that share identity and state. Animal is the natural parent of Dog and Cat. An interface models a capability that can cut across unrelated hierarchies, both Bird and Airplane can fly, but they share no common ancestry. When in doubt, prefer interfaces because they allow more flexible code and easier testing.

Q33. Can an abstract class have a main method?

Yes, an abstract class can contain a main() method and can be run directly from the command line, even though you cannot create an instance of it. The JVM calls main() as a static entry point, which does not require instantiation.

public abstract class AbstractMain {

    public abstract void doSomething();



    public static void main(String[] args) {

        // Cannot do: new AbstractMain() - compile error
        // But can run this class with: java AbstractMain

        System.out.println("Running from an abstract class");
    }
}

Q34. Explain Method Overloading vs Method Overriding

Feature Method Overloading Method Overriding
When resolved Compile time (static binding) Runtime (dynamic binding)
Parameters Must differ (number or type) Must be identical
Return type Can differ Must be same or covariant (subtype)
Access modifier Can change freely Cannot reduce visibility
Polymorphism type Compile-time / static polymorphism Runtime / dynamic polymorphism
Where Same class Subclass overrides parent method

The compile-time vs runtime resolution is the most important distinction here. Overloading is resolved by the compiler based on the method signature. The correct method is selected before the program runs. Overriding is resolved at runtime based on the actual type of the object, not the reference type. This is the mechanism that makes polymorphism work. A subclass object assigned to a parent reference will still call the subclass’s overridden method at runtime.

// OVERLOADING: same name, different parameters (compile-time)
public class Calculator {

    public int add(int a, int b) {
        return a + b;
    }

    public double add(double a, double b) {
        return a + b;
    }

    public int add(int a, int b, int c) {
        return a + b + c;
    }
}



// OVERRIDING: subclass redefines parent method (runtime)

class Animal  {

    public void speak() {
        System.out.println("...");
    }
}



class Dog extends Animal {

    @Override
    public void speak() {
        System.out.println("Woof");
    }
}

💡 Classic interview trap: ‘Can you override a static method?’ No, static methods are resolved at compile time (class-level binding), so they are hidden, not overridden. Calling a static method via a subclass reference calls the parent’s version.

Java Collections Interview Questions

Collections are tested in nearly every Java interview. Knowing the hierarchy, performance trade-offs, and when to use which implementation can be very helpful in the interview.

Q35. What is the Collection Framework in Java?

The Java Collections Framework is a unified architecture of interfaces and classes for storing, manipulating, and retrieving groups of objects. The core hierarchy:

  • Iterable → Collection → List (ArrayList, LinkedList, Vector)
  • Iterable → Collection → Set (HashSet, TreeSet, LinkedHashSet)
  • Iterable → Collection → Queue (PriorityQueue, ArrayDeque)
  • Map (HashMap, TreeMap, LinkedHashMap, ConcurrentHashMap) separate hierarchy

Map is NOT a sub-interface of Collection, it maps keys to values and has its own hierarchy. The framework is in java.util and provides algorithm utilities (Collections.sort(), Collections.binarySearch(), etc.) that work across implementations.

Q36. Difference between an array and a collection?

Feature Array Collection
Size Fixed at creation, cannot resize Dynamic, grows and shrinks automatically
Type safety Compile-time type check Generics provide compile-time safety
Primitives Can store primitives directly Stores only objects (autoboxing for primitives)
Utility methods None, manual loops required Rich API: sort, search, filter, iterate
Null handling Can contain null values Depends on implementation (HashMap allows one null key)

Q37. Difference between ArrayList and LinkedList?

Feature ArrayList LinkedList
Internal structure Dynamic array (contiguous memory) Doubly-linked list (nodes with prev/next pointers)
Random access (get) O(1), direct index access O(n), must traverse from head or tail
Insertion/deletion (middle) O(n), shifts subsequent elements O(1) once the node is found (O(n) to find it)
Memory overhead Low, just the element + array slot High, each node stores an element + two pointers
Best use case Read-heavy access by index Frequent insertions/deletions at the head or tail
// ArrayList - optimized for fast random access (reads)
List<String> arrayList  = new ArrayList<>();



// LinkedList - optimized for fast insert/delete at head/tail
List<String> linkedList = new LinkedList<>();



// LinkedList also implements Deque - can act as queue or stack
Deque<String> deque = new LinkedList<>();

Q38. Difference between HashMap and TreeMap?

Feature HashMap TreeMap
Ordering No guaranteed order Sorted by natural key order or custom Comparator
Null keys One null key allowed No null keys (throws NullPointerException)
Performance O(1) average for get/put O(log n) for get/put (Red-Black tree)
Implementation Hash table (bucket array + linked list / tree) Red-Black balanced BST
Best use case Fast key-value lookups with no ordering needs Sorted map, range queries, navigable operations

Q39. What are fail-fast and fail-safe iterators?

Fail-fast iterators throw ConcurrentModificationException immediately if the underlying collection is modified while being iterated (other than through the iterator itself). Most standard Java iterators (ArrayList, HashMap) are fail-fast.

Fail-safe iterators work on a copy of the collection, so modifications to the original do not affect the iteration. No exception is thrown, but the iterator may not reflect the latest changes. CopyOnWriteArrayList and ConcurrentHashMap use fail-safe iterators.

// FAIL-FAST: throws ConcurrentModificationException
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));

for (String s : list) {
    list.remove(s);  // modifying during iteration - EXCEPTION
}



// FAIL-SAFE: iterates over a snapshot copy, no exception
List<String> cowList = new CopyOnWriteArrayList<>(Arrays.asList("a", "b", "c"));

for (String s : cowList) {
    cowList.remove(s);  // safe - iterating over snapshot
}

Q40. What are Generics in Java and Why Are They Used?

Generics enable type-safe data structures and methods that work with any type while providing compile-time type checking. Without generics, collections stored Object references, requiring explicit casts and risking ClassCastException at runtime.

// Generic class
public class Box<T> {

    private T value;

    public Box(T value) {
        this.value = value;
    }

    public T get() {
        return value;
    }
}



// Usage
Box<String>  strBox = new Box<>("Hello");
Box<Integer> intBox = new Box<>(42);



// Bounded type: T must extend Number
public <T extends Number>
double sum(List<T> list) {

    return list
        .stream()
        .mapToDouble(Number::doubleValue)
        .sum();
}



// Wildcards
// ? extends T → read-only (covariant)
// ? super T   → write-only (contravariant)

Important: generics use type erasure, generic type information is removed at compile time and replaced with Object (or bounds). At runtime, List<String> and List<Integer> are both just List. This is why you cannot do instanceof List<String> or create generic arrays.

Q41. What is the Difference Between HashMap and ConcurrentHashMap?

Feature HashMap ConcurrentHashMap
Thread safety Not thread-safe, concurrent modifications cause data corruption Thread-safe, designed for concurrent use
Null keys/values One null key, multiple null values allowed No null keys or values
Locking mechanism No locking Segment-based locking (Java 7) / bucket-level CAS (Java 8+)
Performance Fastest for single-threaded use High concurrent throughput with minimal contention
Iteration Fail-fast (ConcurrentModificationException) Weakly consistent, no exception
💡 Senior interviewers note: always mention that Hashtable is the legacy thread-safe map (fully synchronized, poor performance). ConcurrentHashMap is the modern replacement; it uses fine-grained locking (Java 7) or CAS operations (Java 8+) for far better concurrent throughput.

Fundamental Multithreading Java Interview Questions

Multithreading separates mid-level from senior Java developers. These questions test your understanding of concurrency, synchronization, and thread safety. For an extended set of problems and scenarios, see Java multithreading interview questions covering thread lifecycle, executor frameworks, and advanced coordination patterns.

Q42. What is a Thread in Java?

A thread is the smallest unit of execution within a program. Java supports true multi-threading through the java.lang.Thread class and the Runnable and Callable interfaces, allowing concurrent task execution within the same process.

Thread lifecycle:

NEW → RUNNABLE → RUNNING → WAITING/BLOCKED/SLEEPING → TERMINATED

// Method 1: Extend Thread class
class MyThread extends Thread {

    public void run() {
        System.out.println("Thread running");
    }
}

new MyThread().start();



// Method 2: Implement Runnable (preferred)
Thread t = new Thread(() -> 
    System.out.println("Lambda thread running")
);

t.start();

Prefer implementing Runnable over extending Thread, as it keeps your class free to extend another class and separates the task logic from thread management.

Q43. What is the difference between a thread and a process?

Feature Process Thread
Memory Separate memory space, isolated from other processes Shares memory space with other threads in the same process
Overhead Heavy, OS-level resource allocation Lightweight; shares process resources
Communication IPC required (pipes, sockets, shared memory) Direct; shared heap memory (requires synchronization)
Creation cost High Low
Failure isolation A crash does not affect other processes A thread crash can crash the whole process

Q44. What is Synchronization?

Synchronization is the mechanism that ensures only one thread at a time can execute a critical section of code, preventing race conditions when multiple threads share mutable state. Java implements synchronization through monitor locks; every Java object has an implicit monitor.

// Shared counter with synchronization
public class Counter {

    private int count = 0;

    

    // Synchronized method: locks entire object
    public synchronized void increment() {
        count++;
    }

    

    // Synchronized block: finer control
    public void decrement() {

        synchronized (this) {
            count--;
        }
    }
}

Synchronized methods lock the entire object. Synchronized blocks lock only the specified object reference. Use them when you need finer control or want to reduce contention by using a dedicated lock object instead of this.

Q45. What is Deadlock?

A deadlock is a situation where two or more threads are permanently blocked, each waiting for a resource held by the other. None can proceed, and the application hangs.
Circular wait (the root cause): Thread A holds Lock1, waits for Lock2 ↔ Thread B holds Lock2, waits for Lock1

Prevention strategies:

  • Lock ordering: always acquire multiple locks in the same fixed sequence across all threads
  • Lock timeout: use tryLock(timeout) from ReentrantLock rather than blocking indefinitely
  • Avoid nested locks: minimize scenarios where a thread holds one lock while acquiring another
  • Use higher-level concurrency utilities: java.util.concurrent classes reduce manual locking errors

Q46. What is a Thread Pool?

A thread pool is a collection of pre-created, reusable threads managed by an ExecutorService. Instead of creating a new thread for every task (expensive), tasks are submitted to the pool and executed by available worker threads.

// Import concurrency utilities
import java.util.concurrent.*;



// Fixed thread pool: always 4 worker threads
ExecutorService fixedPool = 
    Executors.newFixedThreadPool(4);



// Cached pool: grows as needed, reuses idle threads
ExecutorService cachedPool = 
    Executors.newCachedThreadPool();



// Submit tasks
fixedPool.submit(() -> 
    System.out.println("Task 1")
);

fixedPool.submit(() -> 
    System.out.println("Task 2")
);



// Shutdown pool
fixedPool.shutdown();

Benefits: reduced thread creation overhead, bounded resource usage, task queuing. Use newFixedThreadPool for CPU-bound tasks (size = CPU cores). Use newCachedThreadPool for short-lived I/O-bound tasks.

Q47. What is the volatile keyword in Java?

volatile is a field modifier that guarantees visibility across threads; any write to a volatile variable is immediately visible to all other threads that subsequently read it. It establishes a happens-before relationship, preventing stale cached values.

// Visibility control using volatile
public class StatusMonitor {

    private volatile boolean running = true;

    

    // Stop signal
    public void stop() {
        running = false;
    }

    

    // Monitor loop
    public void monitor() {

        while (running) {
            // do work
        }
    }
}

Without volatile, the JVM may cache running in a CPU register or L1 cache, and a thread calling monitor() may never see the update from stop(). volatile forces every read to go directly to main memory.

⚠️ Pro Tip: volatile guarantees visibility but NOT atomicity. Incrementing a volatile int (i++) is a three-step operation (read → increment → write) and is still unsafe without synchronization. For atomic operations on a single variable, use AtomicInteger or AtomicBoolean instead.

Topics like volatile, locks, AtomicInteger, CountDownLatch, and the java.util.concurrent package are covered in depth in Java concurrency interview questions, the dedicated resource for senior-level concurrency preparation.

Java 8+ Features Interview Questions

Java 8 revolutionized the language with functional programming features; these questions are standard in modern Java interviews. To test your knowledge of these topics and beyond, Advanced Java MCQs with answers provides a practical question bank covering Java 8+ features, generics, collections, and JVM internals.

Q48. What is a Functional Interface?

A functional interface is an interface with exactly one abstract method. It can be used as the target type for a lambda expression or method reference. The @FunctionalInterface annotation is optional but recommended; it causes a compile error if the interface accidentally gains a second abstract method.

// Custom functional interface
@FunctionalInterface
public interface Transformer<T, R> {

    R transform(T input);  // single abstract method
    // default methods allowed
}



// Built-in functional interfaces

Predicate<String>  isLong =
    s -> s.length() > 5;  

Function<String, Integer> len =
    String::length;  

Consumer<String>   printer =
    System.out::println;  

Supplier<String>   greeting =
    () -> "Hello";  

Q49. What is a Lambda Expression?

A lambda expression is a concise, anonymous function that implements a functional interface. It eliminates the boilerplate of anonymous inner classes for single-method implementations.

// Before Java 8: anonymous inner class
Runnable r1 = new Runnable() {

    @Override
    public void run() {
        System.out.println("Running");
    }
};



// Java 8+: lambda expression
Runnable r2 = () ->
    System.out.println("Running");



// Lambda with parameters
Comparator<String> byLength =
    (a, b) -> a.length() - b.length();



// Lambda in a stream pipeline
List<String> names = 
    List.of("Alice", "Bob", "Charlie");

names.stream()
     .filter(n -> n.length() > 3)
     .forEach(System.out::println);

Q50. What is the Stream API?

The Stream API provides a functional, declarative way to process sequences of elements, filtering, transforming, and aggregating in a pipeline. Streams are lazy (intermediate operations are not executed until a terminal operation is called) and can be parallelized with a single method call.

// Input list
List<Integer> numbers =
    List.of(1, 2, 3, 4, 5,
            6, 7, 8, 9, 10);



// Stream pipeline
int sumOfEvenSquares =
    numbers.stream()
        .filter(n -> n % 2 == 0)   // keep even numbers
        .map(n -> n * n)            // square each
        .reduce(0, Integer::sum);  // sum all

System.out.println(sumOfEvenSquares);  // 220



// Parallel stream
long count =
    numbers.parallelStream()
        .filter(n -> n > 5)
        .count();

Key characteristics: streams are not data structures (they do not store elements), are lazily evaluated, can only be consumed once, and support sequential and parallel execution modes.

Q51. What is the Optional class?

Optional<T> is a container object that may or may not hold a non-null value. It is designed to replace the null return pattern and make the possibility of absence explicit in the API contract, reducing NullPointerException risk.

import java.util.Optional;



// Creating Optional objects
Optional<String> present =
    Optional.of("hello");

Optional<String> empty =
    Optional.empty();

Optional<String> maybeNull =
    Optional.ofNullable(null);  // safe for null



// Check and retrieve (not recommended)
if (present.isPresent())
    System.out.println(present.get());



// Provide a default
String value =
    empty.orElse("default");



// Transform if present
Optional<Integer> length =
    present.map(String::length);



// Throw if absent
String result =
    present.orElseThrow(() ->
        new RuntimeException("Missing value")
    );

Q52. What are Records in Java? (Java 14+)

A record is a special kind of class designed as an immutable data carrier. The compiler automatically generates a canonical constructor, accessor methods (not getters, just field name with no ‘get’ prefix), and overrides for equals(), hashCode(), and toString().

// Java 16+: record
public record Point(int x, int y) { }



// Usage
Point p = new Point(3, 4);

System.out.println(p);      // Point[x=3, y=4]
System.out.println(p.x());  // 3

Records are implicitly final (cannot be extended) and their fields are final (immutable). They can implement interfaces but cannot extend other classes (except Record implicitly).

Q53. What are Sealed Classes in Java? (Java 17+)

Sealed classes restrict which classes can extend or implement them. The sealed modifier + permits clause defines an exhaustive, closed hierarchy. This enables the compiler to verify exhaustive pattern matching without a default branch.

// Java 17+: sealed class
public sealed class Shape
    permits Circle, Rectangle, Triangle { }



// Allowed subclasses
public final class Circle extends Shape {
    double radius;
}

public final class Rectangle extends Shape {
    double width, height;
}

public non-sealed class Triangle extends Shape {
    double base, height;
}



// Exhaustive switch (pattern matching)
double area = switch (shape) {
    case Circle    c -> Math.PI * c.radius * c.radius;
    case Rectangle r -> r.width * r.height;
    case Triangle  t -> t.base * t.height * 0.5;
};

Sealed classes are a key building block for algebraic data types in Java. They pair with pattern matching (Java 16+) and record patterns (Java 21) for clean, type-safe data processing without instanceof chains.

Common Exception Handling in Java

Exception handling is a guaranteed interview topic; know the hierarchy, checked vs unchecked, and the try-catch-finally nuances. For a deeper set of scenario-based questions on this topic, explore Java exception handling interview questions covering custom exceptions, multi-catch blocks, and exception chaining patterns.

Q54. What are Checked and Unchecked exceptions?

Feature Checked Exception Unchecked Exception
When detected Compile time must be handled Runtime, optional to handle
Must handle? Yes, declare with throws or wrap in try-catch No; can propagate silently
Extends Exception (but not RuntimeException) RuntimeException or Error
Examples IOException, SQLException, FileNotFoundException NullPointerException, ArrayIndexOutOfBoundsException, IllegalArgumentException
Intent Recoverable conditions (missing file, network down) Programming bugs (null dereference, bad array index)

Q55. What is the Exception Hierarchy?

Java’s exception hierarchy is rooted at Throwable:

Throwable

├── Error (OutOfMemoryError, StackOverflowError), JVM errors, generally unrecoverable

└── Exception

├── Checked exceptions (IOException, SQLException …)

└── RuntimeException (NullPointerException, ClassCastException …)

Errors are thrown by the JVM for serious system-level problems; you generally should not catch them. Checked exceptions must be declared or caught. RuntimeException (unchecked) subclasses represent programming errors.

Q56. Can we write try without catch?

Yes, try can be used without catch as long as it is paired with finally, or used as a try-with-resources statement.

// try-finally: cleanup always runs
try {
    riskyOperation();
} finally {
    cleanup();   // always executes
}



// try-with-resources: auto-close
try (
    BufferedReader br =
        new BufferedReader(
            new FileReader("file.txt")
        )
) {
    return br.readLine();
}  // br.close() called automatically

Q57. What is the Difference Between final, finally, and finalize?

Keyword Type Purpose Example
final Modifier keyword Variable: constant. Method: cannot override. Class: cannot extend. final int MAX = 100;
finally Block in exception handling Code that always runs after try/catch, regardless of exception finally { conn.close(); }
finalize Object method (deprecated) Called by GC before an object is garbage collected to allow cleanup @Override protected void finalize() { }
💡 Pro Tip: Always mention that finalize() is deprecated since Java 9 and removed in later versions. Interviewers test version awareness. The modern replacement is java.lang.ref.Cleaner or try-with-resources for deterministic resource management.

Specialized Java Topics

Senior Java interviews often touch on distributed systems, garbage collection, and design patterns. Here are the most common questions.

Q58. What is the CAP Theorem?

The CAP theorem states that a distributed system can only guarantee two of the following three properties simultaneously:

  • Consistency (C): Every read receives the most recent write or an error, all nodes see the same data at the same time
  • Availability (A): Every request receives a (non-error) response, though it may not contain the most recent data
  • Partition Tolerance (P): The system continues operating even when network partitions cause messages between nodes to be lost or delayed

Triangle: C, A, P (choose two)

CA systems (e.g., traditional RDBMS): consistent and available, but fail under network partitions.

CP systems (e.g., HBase, ZooKeeper): consistent under partitions, but may deny requests to maintain consistency.

AP systems (e.g., Cassandra, DynamoDB): available under partitions, but may return stale data.

In practice, network partitions in distributed systems are unavoidable, so real systems must choose between C and A when a partition occurs.

Q59. What is the G1 Garbage Collector?

G1 (Garbage-First) is Java’s default garbage collector since Java 9. Unlike older generational collectors (Young/Old/Permanent generation), G1 divides the heap into equal-sized regions and independently collects whichever regions contain the most garbage first, hence the name.

  • Heap layout: equal-sized regions (default 1–32 MB each), each region can be Eden, Survivor, Old, or Humongous
  • Target pause time: configurable with -XX:MaxGCPauseMillis (default 200 ms), G1 adjusts how many regions it collects to stay within the target
  • Concurrent marking: G1 marks live objects while the application runs, reducing stop-the-world pauses
  • Best for: large heaps (4 GB+) where predictable, low-pause GC is important

For latency-critical applications, ZGC (Java 15+, stable in Java 17) provides sub-millisecond pauses and is increasingly used at scale.

Q60. What is Dependency Injection?

Dependency Injection (DI) is a design pattern where an object’s dependencies are provided from outside (injected) rather than created internally. It is the primary mechanism behind Inversion of Control (IoC) containers like Spring.

// Without DI: tightly coupled
public class OrderService {

    private PaymentService payment =
        new PaymentService();  // hardcoded dependency
}



// With DI: loosely coupled
public class OrderService {

    private final PaymentService payment;

    @Autowired
    public OrderService(PaymentService payment) {
        this.payment = payment;
    }
}

Benefits: testability (mock the dependency in unit tests), flexibility (swap implementations without changing the class), and cleaner architecture. Spring supports constructor injection (preferred), setter injection, and field injection.

Dependency injection is the foundation of the Spring framework, and Spring is the most commonly tested enterprise Java topic at the senior level. To prepare for Spring-specific questions on beans, application context, AOP, and Spring Boot, explore Spring interview questions that cover the full Spring ecosystem interviewers probe.

Q61. What is a RESTful API?

A RESTful API is a web service that follows REST (Representational State Transfer) architectural constraints, using HTTP as the communication protocol.

  • Stateless: Each request contains all information needed, no session state on the server
  • Uniform interface: Resources identified by URLs; HTTP methods define operations
  • Client-server separation: UI and data storage concerns are separated
  • Cacheable: Responses can be marked as cacheable for performance
HTTP Method Operation Example URL Idempotent?
GET Read a resource GET /users/42 Yes
POST Create a resource POST /users No
PUT Replace a resource PUT /users/42 Yes
PATCH Partially update PATCH /users/42 Yes
DELETE Remove a resource DELETE /users/42 Yes

Q62. What is the Singleton Design Pattern?

Singleton ensures a class has exactly one instance throughout the application and provides a global access point to it. There are several implementation approaches; the enum-based approach is the recommended one (Joshua Bloch, Effective Java).

// Approach 1: Enum Singleton (recommended)
public enum DatabaseConnection {

    INSTANCE;

    public void connect() {
        // ...
    }
}

DatabaseConnection.INSTANCE.connect();



// Approach 2: Double-Checked Locking
public class Config {

    private static volatile Config instance;

    private Config() {}

    public static Config getInstance() {

        if (instance == null) {

            synchronized (Config.class) {

                if (instance == null) {
                    instance = new Config();
                }
            }
        }
        return instance;
    }
}

The volatile keyword is essential in double-checked locking; without it, the JVM may partially publish the object (another thread sees a non-null reference before the constructor completes). The enum approach avoids this entirely.

How to Prepare for a Java Interview?

A structured preparation roadmap, from core fundamentals to advanced topics, is the most efficient path to interview readiness.

  • Master Core Java: JVM architecture (JDK/JRE/JVM), data types and memory model (stack vs heap), OOP principles (encapsulation, inheritance, polymorphism, abstraction), and String handling.
  • Deep-dive into Collections and Generics: Know the hierarchy (List, Set, Map, Queue), performance trade-offs between ArrayList vs LinkedList and HashMap vs TreeMap, generics with bounded wildcards, and thread-safe alternatives (ConcurrentHashMap).
  • Practice Multithreading and Concurrency: Thread lifecycle, synchronization, volatile, deadlocks, thread pools (ExecutorService), and java.util.concurrent utilities (ReentrantLock, CountDownLatch, CyclicBarrier).
  • Learn Java 8+ Features: Lambda expressions, functional interfaces, Stream API (filter/map/reduce/collect), Optional, method references, and default methods in interfaces.
  • Solve Coding Problems in Java: Practice LeetCode and HackerRank problems using Java. Focus on String manipulation, array operations, linked lists, trees, and dynamic programming. Time your solutions.
  • Study Advanced Topics: Design patterns (Singleton, Factory, Builder, Observer), dependency injection and Spring basics, garbage collection (G1GC, ZGC), JVM tuning flags, and microservices concepts.
  • Take Mock Interviews: Practice with real interviewers who have worked at FAANG companies, mock sessions reveal gaps that self-study misses. Focus on thinking aloud while coding.

Ready to Crack Software Engineering Interviews at Top Tech Companies?

Cracking top software engineering interviews takes more than knowing how to code. The Software Engineering Interview Prep program by Interview Kickstart is designed to help you master both technical skills and how to present them effectively in interviews. With in-depth training, individualized support, and 1:1 coaching, you’ll learn what top companies actually look for and how to stand out.

You’ll train with FAANG+ instructors who bring real hiring experience, practice through mock interviews in realistic environments, and get structured feedback to improve quickly. The program also supports your overall career growth with resume building, personal branding, and interview strategy. If you’re serious about landing a top software engineering role, this is where preparation turns into results.

Conclusion

This guide has covered the full breadth of Java interview questions, from JVM fundamentals and memory management, through OOP and Collections, to advanced topics including multithreading, Java 8+ features, exception handling, and design patterns. Whether you are preparing as a fresher or reviewing for a senior role, the 60+ questions and answers above reflect what Java interviewers consistently test across companies of all sizes.

Java’s continued dominance in enterprise development is well-documented. According to the Oracle Java developer survey and multiple independent developer reports, Java remains the primary language for large-scale backend systems at companies like Google, Amazon, and Netflix, and shows no signs of slowing in adoption.

For hands-on preparation, Interview Kickstart’s Java curriculum is built and taught by engineers who have been hired at FAANG companies, so your preparation is aligned with what interviewers actually look for, not just what textbooks describe.

Ready to level up your Java interview readiness? Explore and practice deeper on the most tested Java sub-topics.

FAQs: Java Interview Questions

Q1. What are the most commonly asked Java interview questions?

The most consistently tested topics are JDK vs JRE vs JVM, == vs equals(), String immutability, ArrayList vs LinkedList, HashMap internals, multithreading basics, and exception handling. For senior roles, concurrency utilities, JVM garbage collection, and design patterns are added to the mix.

Q2. How do I prepare for a Java interview as a fresher?

Start with core Java syntax and OOP fundamentals (classes, inheritance, interfaces, polymorphism), then learn the Collections framework and exception handling. Practice writing code daily, LeetCode and HackerRank have Java-specific tracks. Follow the preparation roadmap in the section above for a structured sequence.

Q3. What Java topics are asked for 5+ years experience?

Mid-to-senior interviews focus on concurrency (locks, volatile, ExecutorService), design patterns, JVM internals (classloading, GC algorithms, heap tuning), garbage collection strategies (G1, ZGC), microservices architecture with Spring Boot, and system design questions that require Java-specific implementation decisions.

Q4. Is Java still relevant for interviews in 2026?

Yes, Java remains one of the top three most-used languages for enterprise development and is the primary backend language at companies like Google, Amazon, and Netflix. The JetBrains Developer Ecosystem Survey consistently places Java in the top three most widely used languages globally, and Spring Boot adoption continues to grow in microservices architectures.

Q5. What is the difference between core Java and advanced Java?

Core Java covers the language fundamentals: OOP, collections, exceptions, I/O, generics, multithreading, and Java 8+ features. Advanced Java covers enterprise features: JDBC (database connectivity), Servlets and JSP (web layer), Spring and Spring Boot (application framework), REST APIs, and microservices architecture.

References

  1. Employment for software developers is projected to grow 15% from 2024 to 2034
  2. Senior Java Developer Salary

Recommended Reads:

Register for our webinar

Uplevel your career with AI/ML/GenAI

Loading_icon
Loading...
1 Enter details
2 Select webinar slot
By sharing your contact details, you agree to our privacy policy.

Select a Date

Time slots

Time Zone:

IK courses Recommended

Master ML interviews with DSA, ML System Design, Supervised/Unsupervised Learning, DL, and FAANG-level interview prep.

Fast filling course!

Get strategies to ace TPM interviews with training in program planning, execution, reporting, and behavioral frameworks.

Course covering SQL, ETL pipelines, data modeling, scalable systems, and FAANG interview prep to land top DE roles.

Course covering Embedded C, microcontrollers, system design, and debugging to crack FAANG-level Embedded SWE interviews.

Nail FAANG+ Engineering Management interviews with focused training for leadership, Scalable System Design, and coding.

End-to-end prep program to master FAANG-level SQL, statistics, ML, A/B testing, DL, and FAANG-level DS interviews.

Select a course based on your goals

Learn to build AI agents to automate your repetitive workflows

Upskill yourself with AI and Machine learning skills

Prepare for the toughest interviews with FAANG+ mentorship

Register for our webinar

How to Nail your next Technical Interview

Loading_icon
Loading...
1 Enter details
2 Select slot
By sharing your contact details, you agree to our privacy policy.

Select a Date

Time slots

Time Zone:

Almost there...
Share your details for a personalised FAANG career consultation!
Your preferred slot for consultation * Required
Get your Resume reviewed * Max size: 4MB
Only the top 2% make it—get your resume FAANG-ready!

Registration completed!

🗓️ Friday, 18th April, 6 PM

Your Webinar slot

Mornings, 8-10 AM

Our Program Advisor will call you at this time

Register for our webinar

Transform Your Tech Career with AI Excellence

Transform Your Tech Career with AI Excellence

Join 25,000+ tech professionals who’ve accelerated their careers with cutting-edge AI skills

25,000+ Professionals Trained

₹23 LPA Average Hike 60% Average Hike

600+ MAANG+ Instructors

Webinar Slot Blocked

Interview Kickstart Logo

Register for our webinar

Transform your tech career

Transform your tech career

Learn about hiring processes, interview strategies. Find the best course for you.

Loading_icon
Loading...
*Invalid Phone Number

Used to send reminder for webinar

By sharing your contact details, you agree to our privacy policy.
Choose a slot

Time Zone: Asia/Kolkata

Choose a slot

Time Zone: Asia/Kolkata

Build AI/ML Skills & Interview Readiness to Become a Top 1% Tech Pro

Hands-on AI/ML learning + interview prep to help you win

Switch to ML: Become an ML-powered Tech Pro

Explore your personalized path to AI/ML/Gen AI success

Your preferred slot for consultation * Required
Get your Resume reviewed * Max size: 4MB
Only the top 2% make it—get your resume FAANG-ready!
Registration completed!
🗓️ Friday, 18th April, 6 PM
Your Webinar slot
Mornings, 8-10 AM
Our Program Advisor will call you at this time

Get tech interview-ready to navigate a tough job market

Best suitable for: Software Professionals with 5+ years of exprerience
Register for our FREE Webinar

Next webinar starts in

00
DAYS
:
00
HR
:
00
MINS
:
00
SEC

Your PDF Is One Step Away!

The 11 Neural “Power Patterns” For Solving Any FAANG Interview Problem 12.5X Faster Than 99.8% OF Applicants

The 2 “Magic Questions” That Reveal Whether You’re Good Enough To Receive A Lucrative Big Tech Offer

The “Instant Income Multiplier” That 2-3X’s Your Current Tech Salary

Transform Your Tech Career with AI Excellence

Join 25,000+ tech professionals who’ve accelerated their careers with cutting-edge AI skills

Join 25,000+ tech professionals who’ve accelerated their careers with cutting-edge AI skills

Webinar Slot Blocked

Loading_icon
Loading...
*Invalid Phone Number
By sharing your contact details, you agree to our privacy policy.
Choose a slot

Time Zone: Asia/Kolkata

Build AI/ML Skills & Interview Readiness to Become a Top 1% Tech Pro

Hands-on AI/ML learning + interview prep to help you win

Choose a slot

Time Zone: Asia/Kolkata

Build AI/ML Skills & Interview Readiness to Become a Top 1% Tech Pro

Hands-on AI/ML learning + interview prep to help you win

Switch to ML: Become an ML-powered Tech Pro

Explore your personalized path to AI/ML/Gen AI success

Registration completed!

See you there!

Webinar on Friday, 18th April | 6 PM
Webinar details have been sent to your email
Mornings, 8-10 AM
Our Program Advisor will call you at this time