Skip to content

Java Interview Q&A

System Class

What is the system class in Java?

System class is a final class that cannot be instantiated and extended and all of the methods are static and it is used to access system level operations in java.

Main Method Signature

Why the java main method is written as public static void main(String[] args)

The Java main method signature public static void main(String[] args) is specifically designed this way for the JVM (Java Virtual Machine) to be able to find and execute your program. Here's why each part is necessary:

public

  • The method must be accessible from outside the class
  • The JVM needs to call this method from outside your class to start the program
  • If it were private or protected, the JVM couldn't access it

static

  • The method belongs to the class itself, not to any instance
  • The JVM can call the method without creating an object of the class
  • When your program starts, no objects exist yet, so the entry point must be static

void

  • The method doesn't return any value to the JVM
  • The program's exit status is handled differently (through System.exit() if needed)

main

  • This is the exact method name the JVM looks for as the entry point
  • It's a convention established by the Java specification
  • The JVM specifically searches for a method named "main"

String[] args

  • Accepts command-line arguments passed to the program
  • These are stored as an array of strings
  • Even if you don't use command-line arguments, the parameter must be present

Object Class

Name the superclass in java

Superclass is the java object class all the non primitive data types inherit from it. It provides the object methods like toString and equals.

Finalize Keyword

What does the finalize keyword do?

It is used to clean up the activities related to the object before the destruction.

Anonymous Inner Class

What is an anonymous inner class in Java?

It is a local inner class that does not have a name and it should be defined an initialized in a one statement. And it should override the methods.

Example is extending the runnable interface.

Global Variables

Does java support global variables?

No java does not support global variable because It will be harder to debug and it will give side effects if multiple blocks of the code use same variable name. Instead java support the variables that are scoped within classes methods or blocks.

Thread Lifecycle

What is the lifecycle of a thread in Java?

  • New
  • Runnable
  • Running
  • Blocked
  • Terminated

Volatile Variables

What are the volatile variables and what is their purpose?

A volatile variable ensures that the threads always read from the main memory, not from the threads cache. It ensures visibility.

Wrapper Classes

What are the wrapper classes in java

Wrapper classes convert primitive types into Objects, allowing the types to be treated as Objects.

Singleton Pattern

How to make a singleton class in Java

By making the constructor private and provides the single instance of the class using a static method. This pattern is commonly used to manage shared resources.

public final class Singleton {
    private static Singleton instance;
    public String value;

    private Singleton(String value) {
        // The following code emulates slow initialization.
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
        this.value = value;
    }

    public static Singleton getInstance(String value) {
        if (instance == null) {
            instance = new Singleton(value);
        }
        return instance;
    }
}

Thread Safety

Is singleton thread safe?

  • Singletons are not thread safe by default. If multiple threads try to create instance at the same time it could give multiple instances. To prevent this we can synchronize the method that creates the instance.

Creating Threads

How we can make a Thread in Java

  • Extending Thread - Cannot extend another class because java does not support multiple Inheritance.
  • Implementing Runnable - Define the run method and pass it into a thread Object. This is more flexible.

String Pool

What is Java String pool?

String pool in Java is a special memory area that stores strings. It optimizes the memory by sharing memory across identical strings.

Abstract Classes

What is JAVA abstract class?

An abstract class in java is defined with abstract keyword and it can have abstract and non abstract methods. It is used to make the common behavior in one place and leaving the other specified implementations to the sub classes.

Abstract Class vs Interface

How to differentiate between abstract class and interfaces?

  • A class can only extend one abstract class but implement multiple interfaces so the multiple inheritance issue was addressed.
  • Abstract classes can have any access modifiers but the interfaces can only have public static final (constants) only.
  • Abstract classes can have constructors but interfaces cannot.

Default Methods

What is a default method in the interface? Why it is used?

  • Default methods are in java can have implementations within the interface.
  • Default methods were introduced in java 8 to ensure the backward compatibility
  • Because of the default methods, we can add a new functionality to a interface without adding it to all of the implementing classes.
  • If a class implements two interfaces with the same default method then java requires to override it

Try-Catch-Finally

What happens if a return statement is executed inside the try catch block? Does the finally block still executes?

  • Yes the cleanup happens even the return exist.
  • The finally block will not execute if we use the System.exit() during the try catch execution.

Multiple Exceptions

How would we handle multiple exceptions in a single catch block?

try {
    // Code that may throw exceptions
} catch (IOException | SQLException e) {
    // Handle both IOException and SQLException
    System.out.println(e.getMessage());
}

Polymorphism Types

What is compile time polymorphism and run time polymorphism?

Compile time polymorphism happens when the compilation of the code and it is done by method overloading. Method overloading means the same methods may have multiple parameter types defined in few implementations. When the code compiles the compiler will allocate the necessary method according to the parameter type.

class Calculator {
    // Method overloading examples
    int add(int a, int b) {
        return a + b;
    }

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

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

Run time polymorphism is the method overriding behavior. The method to be used will be determine in the run time of the application.

class Animal {
    void makeSound() {
        System.out.println("Some generic sound");
    }
}

class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println("Woof!");
    }
}

class Cat extends Animal {
    @Override
    void makeSound() {
        System.out.println("Meow!");
    }
}

Autoboxing and Unboxing

What is unboxing and Autoboxing in java?

Autoboxing is the process of creating primitive types into the corresponding wrapper classes.

// Autoboxing: int to Integer
int primitiveInt = 42;
Integer wrapperInt = primitiveInt; // Autoboxing happens here

// Autoboxing in collections
ArrayList<Integer> numbers = new ArrayList<>();
numbers.add(10);

Unboxing is the automatic conversion of wrapper classes into their corresponding primitive types.

Integer wrapperInt = new Integer(42);
int primitiveInt = wrapperInt; // Unboxing happens here

// Unboxing in operations
Integer wrapperValue = 100;
int result = wrapperValue + 50;

String Types Comparison

Differentiate between String, StringBuilder and StringBuffer in Java

Feature String (Immutable) StringBuffer (Mutable, Thread-Safe) StringBuilder (Mutable, Not Thread-Safe)
Mutability No Yes Yes
Performance Slow (creates new object) Medium (StringBuffer methods are synchronized) Fast (not synchronized)
Thread-Safety Yes (immutable) Yes (synchronized) No

Constructor Overloading

Can constructor be overloaded?

Yes, We can have multiple constructors with different parameters. It lets you create objects in various ways depending on what information you have at the time.

Immutable Class

How to create immutable class?

  • Declare the class as final
  • Make all the fields final and private to prevent direct access
  • Do not provide setter methods
  • Initialize all fields using constructor

Dynamic Method Dispatch

What is dynamic method dispatch?

It is the way that java decides which method should use at the runtime of the application when the method is overridden in the subclasses.

LinkedList Usage

How to use Java Linked List?

  • When doing frequent insertions and deletions in the middle of a list, linked lists perform better than ArrayList because the array list need to shift all the elements but the linked list only needs to update the pointers of the adjacent nodes.
  • Linked lists are useful for creating queues and stacks as well.

Exception Types

What are checked and unchecked exceptions in java?

  • Checked exceptions are the exceptions that we need to handle manually by adding try catch or adding the throws to the method signature to pass it in the method hierarchy.
  • For unchecked exceptions we don't need that manual try catch or any handling.
  • Unchecked exceptions are the exceptions that extends the RunTimeException class.
  • Checked exceptions are checked at the compile time so that the program wont compile without handling it.

Static Block

What is a static block in java? What are the usages?

When we need to initialize static variable and that initialization requires complex logic then we can have a static block. Static blocks are particularly valuable when you need to set up the class's environment before any instances are created or static methods are called.

class DatabaseConfig {
    private static final Map<String, String> CONNECTION_PARAMS;

    static {
        CONNECTION_PARAMS = new HashMap<>();
        CONNECTION_PARAMS.put("host", "localhost");
        CONNECTION_PARAMS.put("port", "3306");
        CONNECTION_PARAMS.put("user", "admin");
        CONNECTION_PARAMS.put("timeout", "30");
        // More complex initialization logic can go here
    }
}

// With static block
private static final Map<String, String> CONFIG;
static {
    CONFIG = new HashMap<>();
    try {
        Properties props = new Properties();
        props.load(new FileInputStream("config.properties"));
        for (String key : props.stringPropertyNames()) {
            CONFIG.put(key, props.getProperty(key));
        }
    } catch (IOException e) {
        System.err.println("Failed to load configuration: " + e.getMessage());
    }
}

Exception Categories

What are the two types of exceptions in Java? Explain them deeply

  • Checked: Compiler forces you to handle them
  • Unchecked: Compiler doesn't care, your choice to handle

Interface vs Abstract Class

What's the difference between an Interface and an Abstract Class? When would you use one over the other?

Interface:

  • A contract that defines what methods a class must implement
  • All methods are implicitly public and abstract (before Java 8)
  • Can have default and static methods (Java 8+)
  • Supports multiple inheritance
  • Variables are implicitly public, static, and final

Abstract Class:

  • A class that cannot be instantiated directly
  • Can have both abstract and concrete methods
  • Can have instance variables and constructors
  • Supports single inheritance only
  • Can have access modifiers for methods and variables

When to use:

  • Interface: When you want to define a contract for unrelated classes (e.g., Drawable interface for Circle, Rectangle, Text)
  • Abstract Class: When you have related classes sharing common code (e.g., Animal abstract class for Dog, Cat, Bird)
// Interface example
interface Drawable {
    void draw(); // implicitly public abstract
    default void print() { System.out.println("Printing..."); }
}

// Abstract class example
abstract class Animal {
    protected String name;
    public Animal(String name) { this.name = name; }
    public abstract void makeSound();
    public void sleep() { System.out.println(name + " is sleeping"); }
}

Default and Static Methods in Interfaces

Why do Java interfaces have default and static methods?

Default and static methods were added to Java interfaces to:

  1. Enable interface evolution without breaking existing implementations
  2. Support functional programming features introduced in Java 8
  3. Provide utility and factory methods logically related to the interface
  4. Maintain backward compatibility while allowing the language to evolve

This was a pragmatic solution that allowed Java to evolve (particularly to add lambda expressions and streams) while maintaining its commitment to backward compatibility - a core principle of the Java platform.

Design Guidelines:

  • Default methods: Use for interface evolution and providing common implementations
  • Static methods: Use for utility methods and factory methods related to the interface
  • Don't abuse: Interfaces should still primarily define contracts, not become classes

OOP Principles

Explain the main principles of Object-Oriented Programming (OOP). Can you give a real-world example of polymorphism?

The four main principles:

  • Encapsulation: Bundling data and methods together, hiding internal details
  • Inheritance: Creating new classes based on existing ones
  • Abstraction: Hiding complex implementation details, showing only essential features
  • Polymorphism: One interface, multiple implementations
interface PaymentProcessor {
    void processPayment(double amount);
}

class CreditCardProcessor implements PaymentProcessor {
    public void processPayment(double amount) {
        System.out.println("Processing $" + amount + " via Credit Card");
    }
}

class PayPalProcessor implements PaymentProcessor {
    public void processPayment(double amount) {
        System.out.println("Processing $" + amount + " via PayPal");
    }
}

// Usage
PaymentProcessor processor = new CreditCardProcessor(); // or PayPalProcessor
processor.processPayment(100.0); // Different behavior based on actual type

HashMap Internals

How does a HashMap work internally in Java? What happens during a hash collision?

A HashMap in Java is a data structure that stores key-value pairs. Its main advantage is providing constant time performance O(1) for basic operations like put and get, assuming the hash function distributes elements properly among the buckets.

HashMap: Direct Access (O(1) or Constant Time)

When you want to find a value in a HashMap, it performs these super-fast steps:

  1. Calculate Hash: It takes your key (e.g., "Apple Pie") and computes its hashCode().
  2. Find Index: It uses that hash code to instantly calculate an index in its internal array.
  3. Jump and Get: It jumps directly to that array index and retrieves the value.

This process takes roughly the same amount of time whether the HashMap has 10 items or 10 million items. This is called O(1), or constant time, complexity.

What Happens During a Hash Collision?

A hash collision occurs when two or more different keys produce the same hash code, which results in them being mapped to the same index in the underlying array.

HashMap resolves collisions using a technique called Separate Chaining.

  1. LinkedList for Collisions: When a collision occurs, instead of overwriting the existing Node, the HashMap places the new Node at the same index but links it to the existing Node(s). This effectively creates a LinkedList of Node objects at that bucket index.
  2. Searching the List: When retrieving a value from a bucket that contains a LinkedList, the HashMap first uses the key's hashCode() to find the correct index. Then, it iterates through the LinkedList at that index, using the .equals() method to compare the provided key with the key in each Node until it finds a match.

Equality Comparison

What's the difference between == and the .equals() method? What do you need to do to use a custom object as a key in a HashMap?

== operator:

  • Compares references for objects
  • Compares values for primitives

.equals() method:

  • Compares object content/values
  • Must be overridden for meaningful comparison
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2);      // false (different references)
System.out.println(s1.equals(s2)); // true (same content)

// For HashMap keys, you must override both equals() and hashCode()
class Person {
    private String name;
    private int age;

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Person person = (Person) obj;
        return age == person.age && Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

Memory Model

Explain the Java memory model (Heap vs. Stack). Where are objects and primitives stored?

The stack handles short-lived, method-scoped data, while the heap manages longer-lived objects that may be shared across methods and threads.

Stack provides automatic cleanup, while heap requires garbage collection.

Stack Memory:

  • Stores method call frames, local variables, and partial results
  • Optimized for speed
  • Thread-specific (each thread has its own stack providing natural isolation)
  • Stores primitive values and object references
  • LIFO structure, automatically managed

Heap Memory:

  • Stores all objects and instance variables
  • Optimized for flexibility
  • Shared among all threads
  • Divided into Young Generation and Old Generation
  • Managed by Garbage Collector
public void example() {
    int x = 10;           // x stored in stack
    String name = "John"; // reference in stack, "John" object in heap
    Person p = new Person(); // reference in stack, Person object in heap
}

Java Streams

What are Java Streams? Can you provide an example of using filter, map, and collect?

Streams provide a functional approach to process collections.

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Eve");

// Example: Get names longer than 3 characters, convert to uppercase, collect to list
List<String> result = names.stream()
    .filter(name -> name.length() > 3)    // filter: Alice, Charlie, David
    .map(String::toUpperCase)             // map: ALICE, CHARLIE, DAVID  
    .collect(Collectors.toList());        // collect to List

System.out.println(result);

Optional

What is an Optional in Java 8? How does it help in avoiding NullPointerException?

Optional is a container that may or may not contain a value, helping avoid NullPointerException.

// Instead of returning null
public String findUserNameById(int id) {
    // might return null - risky!
    return database.findUser(id)?.getName();
}

// Use Optional
public Optional<String> findUserNameById(int id) {
    User user = database.findUser(id);
    return user != null ? Optional.of(user.getName()) : Optional.empty();
}

// Usage
Optional<String> userName = findUserNameById(123);

// Safe ways to handle Optional
userName.ifPresent(name -> System.out.println("User: " + name));
String name = userName.orElse("Unknown");
String name2 = userName.orElseThrow(() -> new UserNotFoundException());

// Chaining operations
String result = findUserNameById(123)
    .filter(name -> name.length() > 3)
    .map(String::toUpperCase)
    .orElse("DEFAULT");

Lambda Expressions

What are lambda expressions and functional interfaces?

Lambda Expression: Concise way to represent anonymous functions

Functional Interface: Interface with exactly one abstract method

// Functional Interface
@FunctionalInterface
interface Calculator {
    int calculate(int a, int b);
}

// Before lambdas (anonymous class)
Calculator oldWay = new Calculator() {
    @Override
    public int calculate(int a, int b) {
        return a + b;
    }
};

// With lambda
Calculator add = (a, b) -> a + b;
Calculator multiply = (a, b) -> a * b;
Calculator complex = (a, b) -> {
    int result = a + b;
    System.out.println("Result: " + result);
    return result;
};

// Built-in functional interfaces
Predicate<String> isEmpty = s -> s.isEmpty();
Function<String, Integer> length = s -> s.length();
Consumer<String> print = s -> System.out.println(s);
Supplier<String> supplier = () -> "Hello World";

Concurrency

How do you handle concurrency in Java? Explain the synchronized keyword and the java.util.concurrent package

synchronized keyword:

  • Provides mutual exclusion
  • Can be applied to methods or blocks
  • Uses object's intrinsic lock

java.util.concurrent package:

  • Higher-level concurrency utilities
  • Thread pools, atomic variables, concurrent collections
// Synchronized method
public class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++; // Only one thread can execute this at a time
    }

    public synchronized int getCount() {
        return count;
    }
}

// Synchronized block
public void updateData() {
    synchronized(this) {
        // Critical section
        sharedData.update();
    }
}

// Using java.util.concurrent
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

// Thread pool
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.submit(() -> {
    System.out.println("Task executed by: " + Thread.currentThread().getName());
});

// Atomic variables (lock-free)
AtomicInteger atomicCounter = new AtomicInteger(0);
atomicCounter.incrementAndGet(); // Thread-safe without synchronization

// Concurrent collections
ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);

// Future and CompletableFuture
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    return "Hello from another thread!";
});
future.thenAccept(System.out::println);

ConcurrentHashMap

Explain Java Concurrent HashMap

ConcurrentHashMap is a thread-safe and highly scalable implementation of the Map interface in Java. It allows multiple threads to read and write to the map at the same time without data corruption, offering much better performance than alternatives like Hashtable or a synchronized HashMap.

Comparison:

  • HashMap: It is not thread-safe. If multiple threads try to modify it at once, you can end up with corrupted data or even an infinite loop. It's fast, but only for single-threaded use.
  • Hashtable or Collections.synchronizedMap(new HashMap<>()): These are thread-safe, but they achieve it by placing a single lock on the entire map for any read or write operation. This means only one thread can access the map at a time, creating a major performance bottleneck.
  • ConcurrentHashMap avoids the single-lock problem by using a sophisticated, fine-grained locking mechanism. The implementation evolved significantly in Java 8, but the core idea is to never lock the whole map.
    • No Locks for Reads: Read operations (get()) are generally non-blocking. They use memory synchronization techniques (volatile reads) to ensure they get the most recent completed value without ever acquiring a lock. This makes reads extremely fast.
    • Bucket-Level Locking for Writes: The map is internally an array of "buckets" or "nodes." When you need to write data (put(), remove()), ConcurrentHashMap only locks the specific bucket that you are writing to.

When to use:

You should use ConcurrentHashMap whenever you need a Map that will be accessed and modified by multiple threads in a high-performance environment.

  • Caching Systems: A prime example is an in-memory cache where different threads frequently read, add, and update cached data.
  • Application-wide Registries: Storing shared state, like user sessions or application configurations, that multiple request-handling threads need to access.
  • High-Throughput Data Processing: Any scenario where you are processing data with multiple worker threads that need to share a common lookup table.

Comparable vs Comparator

What is the difference between Comparable and Comparator?

  • Comparable: Implement the Comparable interface and override the compareTo method. It self inside the class then it can be used to compare with other objects of the same class.
  • Comparator: Separate class that implements the Comparator interface with the type of the class. It can be used as a machine for comparing two objects. NO need to modify the class and can have multiple sort orders.

HashMap vs TreeMap

Explain the difference between HashMap and TreeMap

  • TreeMap is a sorted map implementation based on a Red-Black tree (self-balancing binary search tree). In TreeMap no null keys are allowed. TreeMap automatically sorts the keys using red black tree.
  • HashMap: Hash table based, O(1) average performance, no ordering, allows one null key. This is not automatically sorted or not guarantee the order of the insertion. If you need to preserve the order of the insertion use LinkedHashMap.

Memory Leaks

What are memory leaks in Java? How to prevent them?

Memory leaks in Java occur when objects are no longer needed by the application but cannot be garbage collected because they're still referenced somewhere in memory.

Examples:

  • Open the input stream and not closed it
  • Objects added to the static lists (never removed by GC)

Serialization

Explain serialization and deserialization. What is serialVersionUID?

  • When we transmitting data over network the classes should be converted into a byte stream and vice versa. This process is called serialization and deserialization.
  • serialVersionUID is use to detect changes in the class (version controlling)

Meta-annotations

What are meta-annotations?

Meta annotations are used to annotation when making other annotations.

Examples:

@Target(ElementType.METHOD) // allow this annotation to methods only
// (METHOD, FIELD, TYPE, etc.).

@Retention(RetentionPolicy.RUNTIME) // available at run time
// (SOURCE, CLASS, RUNTIME).

Exception Chaining

What is exception chaining in java?

Exception chaining is when you handle an exception by throwing a new, different exception that includes the original exception as its cause. This creates a linked list of exceptions, allowing you to trace an error back to its root source.

Example:

// Custom exception for our application
class DataProcessingException extends Exception {
    public DataProcessingException(String message, Throwable cause) {
        super(message, cause);
    }
}

public class FileManager {
    public void processData(String fileName) throws DataProcessingException {
        try {
            // This is a hypothetical method that could throw an IOException
            readFile(fileName); 
        } catch (IOException e) {
            // We catch the low-level IOException...
            // ...and throw our higher-level exception, chaining the original 'e' as the cause.
            throw new DataProcessingException("Failed to process data from file: " + fileName, e);
        }
    }

    // A dummy method to simulate reading a file
    private void readFile(String fileName) throws IOException {
        throw new IOException("Cannot access the specified file.");
    }
}

Stack trace output:

com.example.DataProcessingException: Failed to process data from file: mydata.txt
    at com.example.FileManager.processData(FileManager.java:16)
    ...
Caused by: java.io.IOException: Cannot access the specified file.
    at com.example.FileManager.readFile(FileManager.java:22)
    at com.example.FileManager.processData(FileManager.java:13)
    ...

See the chain of exceptions. This will preserve the stack trace and improve error reporting significantly.

CompletableFuture

What is CompletableFuture? How is it different from Future?

CompletableFuture is an advanced implementation of the Future interface introduced in Java 8. It represents a future result of an asynchronous computation and provides a powerful set of methods to combine, chain, and manage these computations without blocking.

In essence, it's a more flexible and non-blocking way to handle asynchronous tasks compared to the basic Future.

Try-Catch Requirements

Can we have a try without a catch or finally?

No, the try must have either one of them or both of them.


Created with ❤️ by @TharinduEpaz

www.epazingha.me