Java Interview Questions
Prepare for your next tech interview with the most asked Java interview questions and answers. It includes basic to advanced concepts, coding problems, and real-world scenarios for freshers and experienced developers.
Questions for Beginners
1. What is Java?
Java is an object-oriented, high-level, platform-independent programming language developed by Sun Microsystems, which is now owned by Oracle . Java is based on the "Write Once, Run Anywhere" (WORA) principle, which means that Java code is compiled into bytecode that can run on any machine with a Java Virtual Machine (JVM) installed. Java is widely used for developing web applications, enterprise software, mobile applications, and large systems.
2. What are the features of Java?
Object-Oriented: Java is based on OOP concepts like inheritance, encapsulation, abstraction, and polymorphism.
Platform Independent: Java programs run on any system with a JVM.
Secure: Provides built-in security features like bytecode verification and sandboxing.
Robust: Strong memory management and exception handling.
Multithreaded: Supports concurrent execution of multiple threads.
High Performance: Uses Just-In-Time (JIT) compiler for better performance.
3. What is the difference between JDK, JRE, and JVM?
JVM (Java Virtual Machine): It is an engine that runs Java bytecode and makes Java platform independent.
JRE (Java Runtime Environment): It provides the libraries and JVM required to run Java applications.
JDK (Java Development Kit): It includes JRE along with development tools like compiler (javac), debugger, and other utilities needed to develop Java applications.
4. What are variables in Java?
Variables in Java are containers that hold data values during the execution of a program. Every variable has to be declared with a specific data type, which determines the type of value it can hold. Java has three types of variables: local variables, instance variables, and static variables.
Example:
1class Example {
2 int instanceVar = 10; // Instance variable
3 static int staticVar = 20; // Static variable
4
5 void display() {
6 int localVar = 5; // Local variable
7 System.out.println(localVar);
8 }
9}5. What are data types in Java?
Data types in Java define the type of data a variable can store. They are mainly divided into primitive data types and non-primitive (reference) data types.
Primitive Data Types: byte, short, int, long, float, double, char, boolean.
Non-Primitive Data Types: String, Arrays, Classes, Interfaces, etc.
Example:
1int age = 25; // Primitive
2char grade = 'A'; // Primitive
3String name = "Go2x"; // Non-primitive6. What are primitive and non-primitive data types?
In Java, data types are categorized into primitive and non-primitive types based on how they store values.
Primitive Data Types: These store simple values directly in memory and have fixed sizes. They include byte, short, int, long, float, double, char, and boolean.
Non-Primitive Data Types: These store references (memory addresses) to objects rather than the actual data. Examples include String, Arrays, Classes, and Interfaces.
Example:
1int number = 10; // Primitive
2boolean flag = true; // Primitive
3
4String name = "Go2x"; // Non-primitive
5int[] arr = {1, 2, 3}; // Non-primitive7. What is the main method and its signature?
The main method in Java is the entry point of any standalone Java application. The JVM calls this method to start program execution. Its standard signature must be defined exactly as follows:
public static void main(String[] args)
Here, public allows the JVM to access it, static allows it to run without creating an object, void means it does not return any value, and String[] args is used to receive command-line arguments.
8. What are literals in Java?
Literals in Java are any fixed constant values that can be assigned to the variable.
Integer Literals: 10, 0b1010 (binary), 012 (octal), 0x1A (hexadecimal).
Floating-Point Literals: 3.14, 2.5f, 1.2e3.
Character Literals: 'A', '\n'.
String Literals: "Hello".
Boolean Literals: true, false.
Null Literal: null (represents no object reference).
Example:
1int num = 10;
2double pi = 3.14;
3char grade = 'A';
4String message = "Hello";
5boolean flag = true;
6String obj = null;9. What is object-oriented programming (OOP)?
Object-Oriented Programming (OOP) is a programming paradigm based on the concept of objects, which have data (attributes) and methods (functions). OOP is used to organize code into reusable and modular units. OOP primarily emphasizes four principles: Encapsulation, Inheritance, Polymorphism, and Abstraction.
Example:
1class Car {
2 String brand;
3
4 void start() {
5 System.out.println("Car started");
6 }
7}
8
9Car obj = new Car();
10obj.brand = "Toyota";
11obj.start();10. What are the four pillars of OOP? Explain each.
Encapsulation: It is the concept of bundling data (variables) and methods into a single entity (class) and preventing direct access to the data. It is implemented by using private variables and public getter/setter methods.
Inheritance: It is the ability to inherit the properties and behaviors of another class using the
extendskeyword. It supports code reusability.Polymorphism: It is the ability of methods to behave differently depending on the object. It can be implemented in two ways: method overloading (compile-time polymorphism) and method overriding (runtime polymorphism).
Abstraction: It is the ability to hide the implementation details and display only the necessary details to the user. It is implemented by using abstract classes and interfaces.
Example (Inheritance & Polymorphism):
1class Animal {
2 void sound() {
3 System.out.println("Animal makes sound");
4 }
5}
6
7class Dog extends Animal {
8 void sound() {
9 System.out.println("Dog barks");
10 }
11}
12
13Animal obj = new Dog();
14obj.sound();11. What is a class and object?
A class is a template or blueprint that is used to create objects. It holds the properties (variables) and methods that the objects created from it will have. An object is an instance of a class that represents a real-world entity and holds values for the properties defined in the class.
Example:
1class Student {
2 String name;
3
4 void display() {
5 System.out.println(name);
6 }
7}
8
9Student s1 = new Student();
10s1.name = "Rahul";
11s1.display();12. What are constructors in Java?
Constructors in Java are special methods used to initialize objects. They have the same name as the class and are automatically called when an object is created. Constructors are mainly used to assign initial values to instance variables.
Default Constructor: A constructor with no parameters.
Parameterized Constructor: A constructor with parameters to initialize variables with specific values.
Example:
1class Student {
2 String name;
3
4 Student(String n) {
5 name = n;
6 }
7
8 void display() {
9 System.out.println(name);
10 }
11}
12
13Student s1 = new Student("Rahul");
14s1.display();13. What is method overloading?
Method overloading is a feature in Java where multiple methods in the same class have the same name but different parameter lists (different number, type, or order of parameters). It is an example of compile-time polymorphism.
Example:
1class Calculator {
2 int add(int a, int b) {
3 return a + b;
4 }
5
6 double add(double a, double b) {
7 return a + b;
8 }
9}
10
11Calculator obj = new Calculator();
12System.out.println(obj.add(5, 3));
13System.out.println(obj.add(5.5, 3.5));14. What is method overriding?
Method overriding is a feature in Java where a subclass provides a specific implementation of a method that is already defined in its superclass. The method in the child class must have the same name, return type, and parameter list as the method in the parent class. It is an example of runtime polymorphism.
Example:
1class Animal {
2 void sound() {
3 System.out.println("Animal makes sound");
4 }
5}
6
7class Dog extends Animal {
8 @Override
9 void sound() {
10 System.out.println("Dog barks");
11 }
12}
13
14Animal obj = new Dog();
15obj.sound();15. What are wrapper classes?
Wrapper classes in Java are the classes that are used to convert the primitive types into objects. They are part of the java.lang package and enable the use of primitives in collections and other object-oriented facilities. There is a wrapper class for each primitive type.
byte → Byte
short → Short
int → Integer
long → Long
float → Float
double → Double
char → Character
boolean → Boolean
Example:
1int num = 10;
2Integer obj = Integer.valueOf(num); // Boxing
3int value = obj.intValue(); // Unboxing16. What is the difference between == and .equals()?
In Java, == compares primitive values directly and compares object references (memory addresses) for non-primitive types. The .equals() method is used to compare the actual content or logical equality of objects. The behavior of .equals() can be overridden in classes like String.
Example:
1String s1 = new String("Hello");
2String s2 = new String("Hello");
3
4System.out.println(s1 == s2); // false (different references)
5System.out.println(s1.equals(s2)); // true (same content)17. Can Java be said to be the complete object-oriented programming language?
Java is considered a mostly object-oriented programming language because it supports the core OOP principles such as encapsulation, inheritance, polymorphism, and abstraction. However, it is not a purely object-oriented language because it supports primitive data types (like int, char, boolean) which are not objects. Therefore, Java cannot be called a completely pure object-oriented programming language, but it is strongly object-oriented.
Interview Questions for Freshers
1. Explain access modifiers in Java (public, private, protected, default).
Access modifiers in Java define the visibility and accessibility of classes, variables, methods, and constructors. They control where these members can be accessed from.
public: Accessible from anywhere in the program.
private: Accessible only within the same class.
protected: Accessible within the same package and by subclasses.
default (no modifier): Accessible only within the same package.
Example:
1// File: package1/Person.java
2package package1;
3
4public class Person {
5 public String name = "Rahul";
6 private int age = 25;
7 protected String city = "Delhi";
8 String country = "India"; // default
9
10 public int getAge() { // Accessing private variable using public method
11 return age;
12 }
13}
14
15// File: package2/Test.java
16package package2;
17
18import package1.Person;
19
20public class Test {
21 public static void main(String[] args) {
22 Person p = new Person();
23
24 System.out.println(p.name); // Accessible (public)
25 // System.out.println(p.age); // Not accessible (private)
26 // System.out.println(p.city); // Not accessible (protected, different package)
27 // System.out.println(p.country);// Not accessible (default, different package)
28
29 System.out.println(p.getAge()); // Accessing private via public method
30 }
31}2. What are packages and why are they used?
A package in Java is a namespace that helps to organize related classes, interfaces, and sub-packages into a structured directory. It assists in grouping logically related code together, prevents name conflicts, and enhances code maintainability. Packages also facilitate access protection by controlling visibility using access modifiers and assist in managing large projects.
Java provides two types of packages: built-in packages (like java.util, java.lang) and user-defined packages created by developers.
Example:
1// File: com/example/Calculator.java
2package com.example;
3
4public class Calculator {
5 public int add(int a, int b) {
6 return a + b;
7 }
8}
9
10// File: Main.java
11import com.example.Calculator;
12
13public class Main {
14 public static void main(String[] args) {
15 Calculator c = new Calculator();
16 System.out.println(c.add(5, 3));
17 }
18}3. How do you declare and use arrays?
An array in Java is a collection of elements of the same data type stored in contiguous memory locations. Arrays are used to store multiple values in a single variable instead of declaring separate variables for each value.
Declaration and Initialization:
1int[] numbers; // Declaration
2numbers = new int[5]; // Memory allocation
3
4int[] marks = {90, 85, 88}; // Declaration + InitializationUsing an Array:
1public class Main {
2 public static void main(String[] args) {
3 int[] marks = {90, 85, 88};
4
5 System.out.println(marks[0]); // Access element
6
7 for (int i = 0; i < marks.length; i++) {
8 System.out.println(marks[i]); // Iterate array
9 }
10 }
11}4. What are strings in Java?
Strings in Java are objects that represent a sequence of characters. They are instances of the String class from the java.lang package. Strings in Java are immutable, which means once a String object is created, its value cannot be changed.
Strings can be created in two ways:
1String s1 = "Hello"; // Using string literal
2String s2 = new String("Hello"); // Using new keywordExample of usage:
1public class Main {
2 public static void main(String[] args) {
3 String name = "Rahul";
4 System.out.println(name.length());
5 System.out.println(name.toUpperCase());
6 }
7}5. What’s the difference between String, StringBuffer, and StringBuilder?
String, StringBuffer, and StringBuilder are classes used to handle character sequences in Java, but they differ in mutability and thread-safety.
String: Immutable. Once created, its value cannot be changed. Any modification creates a new object.
StringBuffer: Mutable and thread-safe. Methods are synchronized, making it slower but safe in multithreaded environments.
StringBuilder: Mutable but not thread-safe. Faster than StringBuffer and preferred in single-threaded environments.
Example:
1String s = "Hello";
2s = s + " World"; // Creates new object
3
4StringBuffer sb = new StringBuffer("Hello");
5sb.append(" World");
6
7StringBuilder sb2 = new StringBuilder("Hello");
8sb2.append(" World");6. What is exception handling?
Exception handling in Java is a process of handling runtime errors in such a way that the normal flow of the program is not affected. It provides the facility to handle errors using specific keywords.
Java provides the following keywords for exception handling: try, catch, finally, throw, and throws.
Example:
1public class Main {
2 public static void main(String[] args) {
3 try {
4 int result = 10 / 0;
5 System.out.println(result);
6 } catch (ArithmeticException e) {
7 System.out.println("Cannot divide by zero");
8 } finally {
9 System.out.println("Execution completed");
10 }
11 }
12}7. What is the difference between checked and unchecked exceptions?
In Java, exceptions are categorized into checked and unchecked exceptions based on when they are checked and handled.
Checked Exceptions: These are checked at compile time. The compiler forces the programmer to handle them using
try-catchor declare them usingthrows. Examples include IOException and SQLException.Unchecked Exceptions: These occur at runtime and are not checked at compile time. They usually result from programming errors. Examples include ArithmeticException and NullPointerException.
Example:
1// Checked Exception Example
2import java.io.*;
3
4class Test {
5 public static void main(String[] args) throws IOException {
6 FileReader file = new FileReader("test.txt");
7 }
8}
9
10// Unchecked Exception Example
11int result = 10 / 0; // ArithmeticException at runtime8. What is the purpose of finally?
The finally block in Java is used to execute important code such as resource cleanup, regardless of whether an exception occurs or not. It always executes after the try and catch blocks, except in cases like system shutdown or JVM crash. It is commonly used to close files, database connections, or release resources.
Example:
1public class Main {
2 public static void main(String[] args) {
3 try {
4 int result = 10 / 0;
5 } catch (ArithmeticException e) {
6 System.out.println("Exception caught");
7 } finally {
8 System.out.println("This will always execute");
9 }
10 }
11}9. What are custom exceptions?
Custom exceptions in Java are user-defined exception classes created to handle specific application-related errors. They are defined by extending either the Exception class (for checked exceptions) or the RuntimeException class (for unchecked exceptions). Custom exceptions help make error handling more meaningful and specific to business logic.
Example:
1class InvalidAgeException extends Exception {
2 public InvalidAgeException(String message) {
3 super(message);
4 }
5}
6
7public class Main {
8 public static void main(String[] args) {
9 try {
10 int age = 15;
11 if (age < 18) {
12 throw new InvalidAgeException("Age must be 18 or above");
13 }
14 } catch (InvalidAgeException e) {
15 System.out.println(e.getMessage());
16 }
17 }
18}10. What is collection framework?
The Collection Framework in Java is a uniform architecture that offers classes and interfaces to store, manipulate, and manage a collection of objects in an efficient manner. It is a part of the java.util package and includes interfaces like List, Set, Queue, and Map, along with their implementations such as ArrayList, HashSet, LinkedList, and HashMap. It simplifies data handling and improves performance by providing ready-made data structures and algorithms.
Example:
1import java.util.*;
2
3public class Main {
4 public static void main(String[] args) {
5 List<String> names = new ArrayList<>();
6 names.add("John");
7 names.add("Rahul");
8
9 for (String name : names) {
10 System.out.println(name);
11 }
12 }
13}11. What are List, Set, and Map interfaces?
List, Set, and Map are core interfaces of the Java Collection Framework that define different ways of storing and managing groups of objects.
List: An ordered collection that allows duplicate elements. Elements can be accessed by index. Common implementations include ArrayList and LinkedList.
Set: A collection that does not allow duplicate elements. It does not guarantee insertion order (except LinkedHashSet). Common implementations include HashSet and TreeSet.
Map: Stores data in key-value pairs. Keys must be unique, but values can be duplicated. It is not a sub-interface of Collection. Common implementations include HashMap and TreeMap.
Example:
1import java.util.*;
2
3public class Main {
4 public static void main(String[] args) {
5 List<String> list = new ArrayList<>();
6 list.add("A");
7 list.add("A"); // duplicates allowed
8
9 Set<String> set = new HashSet<>();
10 set.add("A");
11 set.add("A"); // duplicates not allowed
12
13 Map<Integer, String> map = new HashMap<>();
14 map.put(1, "John");
15 map.put(2, "Rahul");
16
17 System.out.println(list);
18 System.out.println(set);
19 System.out.println(map);
20 }
21}12. What is ArrayList vs LinkedList?
ArrayList and LinkedList are both implementations of the List interface in Java, but they differ in internal structure and performance characteristics.
ArrayList: Uses a dynamic array internally. Provides fast random access (O(1)) but slower insertion and deletion in the middle (O(n)).
LinkedList: Uses a doubly linked list internally. Slower random access (O(n)) but faster insertion and deletion (O(1)) if the node reference is known.
Example:
1import java.util.*;
2
3public class Main {
4 public static void main(String[] args) {
5 List<String> arrayList = new ArrayList<>();
6 List<String> linkedList = new LinkedList<>();
7
8 arrayList.add("A");
9 linkedList.add("A");
10
11 System.out.println(arrayList.get(0));
12 System.out.println(linkedList.get(0));
13 }
14}13. What is HashMap vs Hashtable?
HashMap and Hashtable are both implementations of the Map interface used to store key-value pairs, but they differ in synchronization, performance, and handling of null values.
HashMap: Not synchronized (not thread-safe), faster in single-threaded environments, allows one null key and multiple null values.
Hashtable: Synchronized (thread-safe), slower due to synchronization overhead, does not allow null keys or null values.
Example:
1import java.util.*;
2
3public class Main {
4 public static void main(String[] args) {
5 HashMap<Integer, String> map = new HashMap<>();
6 map.put(null, "Rahul"); // Allowed in HashMap
7
8 Hashtable<Integer, String> table = new Hashtable<>();
9 // table.put(null, "Rahul"); // NullPointerException
10
11 System.out.println(map);
12 System.out.println(table);
13 }
14}14. How does HashMap work internally?
HashMap in Java stores data in key-value pairs and works based on hashing. Internally, it uses an array of buckets where each bucket can store multiple entries.
When a key-value pair is inserted, the hash code of the key is calculated using the
hashCode()method.The hash code determines the index (bucket) in the internal array where the entry will be stored.
If multiple keys map to the same bucket (collision), they are stored using a linked list (or a balanced tree in Java 8+ if the bucket becomes large).
When retrieving a value, HashMap again calculates the hash code and uses the
equals()method to find the correct key inside the bucket.
Example:
1import java.util.*;
2
3public class Main {
4 public static void main(String[] args) {
5 HashMap<Integer, String> map = new HashMap<>();
6 map.put(1, "John");
7 map.put(2, "Rahul");
8
9 System.out.println(map.get(1));
10 }
11}15. What is multithreading?
Multithreading in Java is a concept that enables a Java program to run multiple threads or processes simultaneously. A thread in Java is a lightweight process that runs in parallel and helps to improve the performance of a program, especially in applications such as games, web servers, and background processing.
Threads can be created in two main ways: by extending the Thread class or by implementing the Runnable interface.
Example:
1class MyThread extends Thread {
2 public void run() {
3 System.out.println("Thread is running");
4 }
5}
6
7public class Main {
8 public static void main(String[] args) {
9 MyThread t1 = new MyThread();
10 t1.start();
11 }
12}Interview Questions for Experienced
1. What are generics in Java?
Generics in Java allow classes, interfaces, and methods to operate on specific data types while providing compile-time type safety. They enable you to define a parameterized type using angle brackets <>, which helps avoid explicit type casting and reduces runtime errors.
Generics improve code reusability and readability by allowing a single class or method to work with different data types while maintaining strict type checking at compile time.
Example:
1import java.util.*;
2
3public class Main {
4 public static void main(String[] args) {
5 List<String> names = new ArrayList<>();
6 names.add("Rahul");
7 // names.add(10); // Compile-time error
8
9 for (String name : names) {
10 System.out.println(name);
11 }
12 }
13}2. Explain fail-fast vs fail-safe iterators.
Fail-fast and fail-safe iterators define how collections behave when they are modified during iteration.
Fail-fast Iterator: Throws
ConcurrentModificationExceptionif the collection is structurally modified after the iterator is created (except for the remove method of the iterator itself). Examples include ArrayList and HashMap.Fail-safe Iterator: Does not throw an exception if the collection is modified during iteration because it operates on a clone or snapshot of the collection. Examples include CopyOnWriteArrayList and ConcurrentHashMap.
Example (Fail-fast):
1import java.util.*;
2
3public class Main {
4 public static void main(String[] args) {
5 List<String> list = new ArrayList<>();
6 list.add("A");
7 list.add("B");
8
9 for (String s : list) {
10 list.add("C"); // Causes ConcurrentModificationException
11 }
12 }
13}3. Difference between Thread and Runnable.
In Java, both Thread and Runnable are used to create threads, but they differ in design and flexibility.
Thread: A class that can be subclassed to make a new thread. It combines the functionality of a thread and the task in a single class. Because Java does not support multiple inheritance, if a class is subclassed from the Thread class, it cannot subclass any other class.
Runnable: An interface that contains only the run() method. It divides the task and the thread mechanism into two separate classes, so it can extend another class, which is more flexible and often preferred.
Example:
1// Using Thread class
2class MyThread extends Thread {
3 public void run() {
4 System.out.println("Thread running");
5 }
6}
7
8// Using Runnable interface
9class MyRunnable implements Runnable {
10 public void run() {
11 System.out.println("Runnable running");
12 }
13}
14
15public class Main {
16 public static void main(String[] args) {
17 MyThread t1 = new MyThread();
18 t1.start();
19
20 Thread t2 = new Thread(new MyRunnable());
21 t2.start();
22 }
23}4. What is synchronized keyword?
The synchronized keyword in Java is used to control access to shared resources in a multithreaded environment. It ensures that only one thread can execute a synchronized method or block at a time, preventing race conditions and ensuring thread safety.
It can be applied to entire methods or specific code blocks.
Example:
1class Counter {
2 private int count = 0;
3
4 public synchronized void increment() {
5 count++;
6 }
7}
8
9public class Main {
10 public static void main(String[] args) {
11 Counter counter = new Counter();
12
13 Thread t1 = new Thread(() -> {
14 for (int i = 0; i < 1000; i++) counter.increment();
15 });
16
17 Thread t2 = new Thread(() -> {
18 for (int i = 0; i < 1000; i++) counter.increment();
19 });
20
21 t1.start();
22 t2.start();
23 }
24}5. What is deadlock and how to prevent it?
Deadlock in Java occurs when two or more threads are blocked forever, each waiting for a resource held by the other. As a result, none of the threads can proceed, and the program becomes stuck.
Deadlock can be prevented by following best practices such as acquiring locks in a consistent order, avoiding nested locks when possible, using timeout mechanisms like tryLock(), and minimizing the scope of synchronized blocks.
Example of Deadlock:
1class Test {
2 static final Object lock1 = new Object();
3 static final Object lock2 = new Object();
4
5 public static void main(String[] args) {
6 Thread t1 = new Thread(() -> {
7 synchronized (lock1) {
8 synchronized (lock2) {
9 System.out.println("Thread 1 acquired both locks");
10 }
11 }
12 });
13
14 Thread t2 = new Thread(() -> {
15 synchronized (lock2) {
16 synchronized (lock1) {
17 System.out.println("Thread 2 acquired both locks");
18 }
19 }
20 });
21
22 t1.start();
23 t2.start();
24 }
25}6. What is lambda expression?
A lambda expression in Java is a concise way to represent an anonymous function (a function without a name) that can be passed as an argument. It was introduced in Java 8 and is mainly used with functional interfaces to enable functional programming features.
Syntax:
1(parameters) -> expression
2
3// or
4
5(parameters) -> {
6 // body
7}Example:
1import java.util.*;
2
3public class Main {
4 public static void main(String[] args) {
5 List<String> names = Arrays.asList("John", "Rahul", "Aman");
6
7 names.forEach(name -> System.out.println(name));
8 }
9}7. What are functional interfaces?
A functional interface in Java is an interface that has exactly one abstract method. It is the basis for lambda expressions and method references, which provide functional programming capabilities added to Java in version 8.
A functional interface can have more than one default or static method but only one abstract method. They are usually annotated with @FunctionalInterface to indicate their purpose.
Example:
1@FunctionalInterface
2interface MyFunctionalInterface {
3 void display();
4}
5
6public class Main {
7 public static void main(String[] args) {
8 MyFunctionalInterface obj = () -> System.out.println("Hello");
9 obj.display();
10 }
11}8. What is the Stream API?
The Stream API in Java, which was introduced in Java 8, is a way of processing a collection of data in a functional and declarative programming paradigm. It enables operations like filtering, mapping, sorting, and collecting data without altering the original data source. Streams make programming cleaner and more concise using lambda expressions.
Stream operations are divided into intermediate operations (like filter(), map()) and terminal operations (like forEach(), collect()).
Example:
1import java.util.*;
2import java.util.stream.*;
3
4public class Main {
5 public static void main(String[] args) {
6 List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
7
8 List<Integer> evenNumbers = numbers.stream()
9 .filter(n -> n % 2 == 0)
10 .collect(Collectors.toList());
11
12 System.out.println(evenNumbers);
13 }
14}9. What are annotations in Java?
Annotations in Java are metadata that provide additional information about classes, methods, variables, or other program elements. They do not change the program logic directly but are used by the compiler or runtime environment to provide instructions or configuration.
Java provides built-in annotations such as @Override, @Deprecated, and @SuppressWarnings. Developers can also create custom annotations.
Example:
1class Parent {
2 void display() {}
3}
4
5class Child extends Parent {
6 @Override
7 void display() {
8 System.out.println("Method overridden");
9 }
10}10. What is garbage collection?
Garbage Collection in Java is an automated memory management system that deletes objects from memory that are no longer reachable or referenced by the application. This is helpful in preventing memory leaks and enhancing the performance of the application by releasing unused memory from the heap.
The Java Virtual Machine (JVM) runs the Garbage Collector periodically to identify and clean up unused objects. Developers can request garbage collection using System.gc(), but it is not guaranteed to execute immediately.
Example:
1public class Main {
2 public static void main(String[] args) {
3 String str = new String("Hello");
4 str = null; // Object becomes eligible for garbage collection
5
6 System.gc();
7 }
8}11. How does JVM memory management work?
JVM memory management is responsible for allocating and deallocating memory for Java applications. The JVM divides memory into different runtime areas to efficiently manage objects, methods, and threads.
Heap: Stores objects and instance variables. Garbage collection runs here.
Stack: Stores method calls, local variables, and references. Each thread has its own stack.
Method Area (MetaSpace): Stores class metadata, static variables, and method information.
PC Register and Native Method Stack: Used for thread execution and native method handling.
The Garbage Collector automatically frees memory in the heap when objects are no longer referenced, ensuring efficient memory usage.
12. What is stack vs heap memory?
Stack and Heap are two primary memory regions in Java that are used during the execution of the program. They are different in terms of their functionality, organization, and life cycle.
Stack Memory: It holds method calls, local variables, and references. It is organized in LIFO (Last In, First Out) order. Every thread has its own stack, and memory is automatically released once the method execution is finished.
Heap Memory: It holds objects and variables. It is shared by all threads, and memory is managed by the Garbage Collector.
Example:
1class Person {
2 String name; // Stored in Heap
3}
4
5public class Main {
6 public static void main(String[] args) {
7 int age = 25; // Stored in Stack
8 Person p = new Person(); // Object stored in Heap, reference in Stack
9 }
10}13. What is the difference between shallow and deep copy?
Shallow copy and deep copy are methods of copying objects in Java, especially when objects have references to other objects.
Shallow Copy: It creates a new object but copies the references of the nested objects rather than copying them. The original and copied objects will have the same referenced objects.
Deep Copy: It creates a new object and also copies all the referenced objects, so that no changes in the objects are affected.
Example:
1class Address {
2 String city;
3 Address(String city) { this.city = city; }
4}
5
6class Person implements Cloneable {
7 String name;
8 Address address;
9
10 Person(String name, Address address) {
11 this.name = name;
12 this.address = address;
13 }
14
15 protected Object clone() throws CloneNotSupportedException {
16 return super.clone(); // Shallow copy
17 }
18}
19
20public class Main {
21 public static void main(String[] args) throws Exception {
22 Address addr = new Address("Delhi");
23 Person p1 = new Person("Aman", addr);
24 Person p2 = (Person) p1.clone();
25
26 p2.address.city = "Mumbai";
27 System.out.println(p1.address.city); // Also changes (shallow copy)
28 }
29}14. What is pass-by-value in Java?
In Java, all arguments to methods are passed by value. This means that a copy of the variable is passed to the method. For primitive types, a copy of the value is made. For objects, a copy of the reference to the object is made, not the object itself.
Since only a copy is passed, if a primitive variable is modified in a method, it will not affect the original variable. However, if an object is modified in a method, the internal state of the object can be changed, but the original reference cannot be changed.
Example:
1class Test {
2 void change(int x) {
3 x = 20;
4 }
5
6 public static void main(String[] args) {
7 int num = 10;
8 Test t = new Test();
9 t.change(num);
10 System.out.println(num); // Still 10
11 }
12}15. What are volatile variables?
A volatile variable in Java is a variable declared with the volatile keyword to ensure visibility of changes across multiple threads. It guarantees that any thread accessing the variable will read the most recent value directly from main memory instead of using a cached copy.
Volatile ensures visibility but does not provide atomicity, meaning it cannot prevent race conditions in compound operations like count++.
Example:
1class Shared {
2 volatile boolean flag = false;
3
4 void setFlag() {
5 flag = true;
6 }
7}16. What is JIT compiler?
The JIT compiler is a part of the JVM that enhances the performance of Java applications by compiling the bytecode into native machine code. This is because, instead of interpreting the bytecode line by line, the JIT compiler translates the hotspots of the code into optimized machine code, which runs faster.
When a Java program is executed, the JVM first interprets the bytecode. When some methods are repeatedly invoked, the JIT compiler translates them into native code and stores them in memory for fast execution.
17. How is an infinite loop declared in Java?
An infinite loop in Java is a loop that runs continuously without a terminating condition. It is usually declared using a loop where the condition always evaluates to true.
Examples:
1// Using for loop
2for (;;) {
3 System.out.println("Infinite loop");
4}
5
6// Using while loop
7while (true) {
8 System.out.println("Infinite loop");
9}18. What is a singleton class in Java? And How to implement a singleton class?
A Singleton class in Java is a class that allows only one instance (object) to be created and provides a global access point to that instance. It is commonly used for shared resources such as configuration settings, logging, or database connections.
To implement a Singleton class:
Make the constructor
privateto prevent external object creation.Create a
private staticinstance of the class.Provide a
public staticmethod to return the instance.
Example (Eager Initialization):
1class Singleton {
2 private static final Singleton instance = new Singleton();
3
4 private Singleton() {}
5
6 public static Singleton getInstance() {
7 return instance;
8 }
9}
10
11public class Main {
12 public static void main(String[] args) {
13 Singleton obj1 = Singleton.getInstance();
14 Singleton obj2 = Singleton.getInstance();
15
16 System.out.println(obj1 == obj2); // true
17 }
18}19. What is a Comparator in Java?
A Comparator in Java is an interface used to define custom sorting logic for objects. It is part of the java.util package and is used when you want to sort objects based on different criteria without modifying the original class.
The Comparator interface contains the compare() method, which compares two objects and returns a negative, zero, or positive value based on their order.
Example:
1import java.util.*;
2
3class Student {
4 String name;
5 int age;
6
7 Student(String name, int age) {
8 this.name = name;
9 this.age = age;
10 }
11}
12
13public class Main {
14 public static void main(String[] args) {
15 List<Student> list = new ArrayList<>();
16 list.add(new Student("Aman", 25));
17 list.add(new Student("Rahul", 22));
18
19 Collections.sort(list, (s1, s2) -> s1.age - s2.age);
20
21 for (Student s : list) {
22 System.out.println(s.name + " " + s.age);
23 }
24 }
25}20. What happens if there are multiple main methods inside one class in Java?
If there are multiple main methods inside one class in Java, it depends on their method signatures. If two methods have the exact same signature public static void main(String[] args), the code will not compile because duplicate methods with identical signatures are not allowed. However, if the main methods have different parameter lists (method overloading), it is allowed, but the JVM will only execute the main method with the exact signature public static void main(String[] args) when the program starts.
Example:
1public class Main {
2
3 public static void main(String[] args) {
4 System.out.println("Original main method");
5 }
6
7 public static void main(int x) {
8 System.out.println("Overloaded main method");
9 }
10}
1121. How does the size of ArrayList grow dynamically? And also state how it is implemented internally.
ArrayList in Java grows dynamically when its capacity is exceeded. Internally, it is implemented using a resizable array. When the current array becomes full and a new element is added, ArrayList creates a new larger array and copies the existing elements into it.
By default, when resizing is required, the new capacity is increased to approximately 1.5 times the old capacity (oldCapacity + oldCapacity/2). This resizing operation involves creating a new array and copying elements using internal methods like Arrays.copyOf().
Internally, ArrayList maintains:
A transient Object array to store elements.
An integer variable to track the current size.
Conceptual Example:
1import java.util.*;
2
3public class Main {
4 public static void main(String[] args) {
5 ArrayList<Integer> list = new ArrayList<>(2);
6 list.add(1);
7 list.add(2);
8 list.add(3); // Triggers resizing
9
10 System.out.println(list);
11 }
12}Advanced Interview Questions
1. What is the Java memory model?
The Java Memory Model (JMM) describes the interaction between threads using memory and how changes made by one thread are made visible to other threads. The JMM provides rules for reading and writing shared variables in a multithreaded environment.
The JMM states that every thread has its own working memory (cache), and shared variables are stored in main memory. Threads read values from main memory into their working memory and write back updated values. The keywordsvolatile, synchronized, and final help enforce visibility and ordering guarantees between threads.
2. What are enums in Java?
Enums in Java are special data types used to define a fixed set of constant values. They are declared using the enum keyword and are type-safe, meaning they prevent invalid values from being assigned.
Enums can contain variables, methods, and constructors, making them more powerful than simple constants. Internally, every enum extends the java.lang.Enum class.
Example:
1enum Day {
2 MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY
3}
4
5public class Main {
6 public static void main(String[] args) {
7 Day today = Day.MONDAY;
8 System.out.println(today);
9 }
10}3. What is the difference between abstract class and interface?
Abstract class and interface are both used to achieve abstraction in Java, but they differ in structure and usage.
Abstract Class: Declared using the
abstractkeyword. It can have abstract and non-abstract methods, constructors, and instance variables. A class can extend only one abstract class.Interface: Declared using the
interfacekeyword. It contains abstract methods by default (and can have default/static methods in Java 8+). A class can implement multiple interfaces.
Example:
1abstract class Animal {
2 abstract void sound();
3 void sleep() {
4 System.out.println("Sleeping");
5 }
6}
7
8interface Pet {
9 void play();
10}
11
12class Dog extends Animal implements Pet {
13 void sound() {
14 System.out.println("Bark");
15 }
16
17 public void play() {
18 System.out.println("Playing");
19 }
20}4. What are inner and anonymous classes?
Inner classes in Java are classes that are defined inside another class. They are used to group classes and improve encapsulation. An inner class has access to the members of the outer class.
An anonymous class is a special type of inner class that has no name. It is declared and instantiated in a single statement and is often used to implement an interface or an abstract class.
Example:
1class Outer {
2 int x = 10;
3
4 class Inner {
5 void display() {
6 System.out.println(x);
7 }
8 }
9}
10
11public class Main {
12 public static void main(String[] args) {
13 Outer outer = new Outer();
14 Outer.Inner inner = outer.new Inner();
15 inner.display();
16
17 // Anonymous class
18 Runnable r = new Runnable() {
19 public void run() {
20 System.out.println("Anonymous class running");
21 }
22 };
23 r.run();
24 }
25}5. What is reflection?
Reflection in Java is a feature that allows a program to inspect and modify classes, methods, fields, and constructors at runtime. It is part of the java.lang.reflect package and is commonly used in frameworks, dependency injection, and testing tools.
Using reflection, you can load classes dynamically, access private members, and invoke methods at runtime even if their names are not known at compile time.
Example:
1class Person {
2 private String name = "Ankit";
3}
4
5public class Main {
6 public static void main(String[] args) throws Exception {
7 Class<?> cls = Class.forName("Person");
8 Object obj = cls.getDeclaredConstructor().newInstance();
9
10 java.lang.reflect.Field field = cls.getDeclaredField("name");
11 field.setAccessible(true);
12 System.out.println(field.get(obj));
13 }
14}6. What are design patterns? (Singleton, Factory, Observer)
Design patterns are reusable solutions to common software design problems. They provide best practices for structuring code, improving maintainability, flexibility, and scalability.
Singleton Pattern: It ensures that a class has only one instance and that instance can be accessed globally. It is used for configuration and logging purposes.
Factory Pattern: It offers an interface for creating objects but allows subclasses to decide which class to instantiate. It helps in loose coupling.
Observer Pattern: It establishes a one-to-many relationship between objects. When an object changes state, all its dependents are automatically notified and updated.
Simple Example (Factory Pattern):
1interface Shape {
2 void draw();
3}
4
5class Circle implements Shape {
6 public void draw() {
7 System.out.println("Circle");
8 }
9}
10
11class ShapeFactory {
12 public static Shape getShape(String type) {
13 if (type.equals("circle")) {
14 return new Circle();
15 }
16 return null;
17 }
18}
19
20public class Main {
21 public static void main(String[] args) {
22 Shape shape = ShapeFactory.getShape("circle");
23 shape.draw();
24 }
25}7. Explain the Singleton pattern.
The Singleton pattern is a creational design pattern that ensures a class has only one instance and provides a global point of access to that instance. It is commonly used when exactly one object is needed to coordinate actions across a system, such as configuration managers, loggers, or database connections.
To implement Singleton:
Make the constructor
privateto prevent object creation from outside.Create a
private staticinstance of the class.Provide a
public staticmethod to return the instance.
Example :
1class Singleton {
2 private static Singleton instance;
3
4 private Singleton() {}
5
6 public static Singleton getInstance() {
7 if (instance == null) {
8 instance = new Singleton();
9 }
10 return instance;
11 }
12}
13
14public class Main {
15 public static void main(String[] args) {
16 Singleton obj1 = Singleton.getInstance();
17 Singleton obj2 = Singleton.getInstance();
18
19 System.out.println(obj1 == obj2); // true
20 }
21}8. What is dependency injection?
Dependency Injection (DI) is a design pattern in which an object receives its dependencies from an external source instead of creating them itself. It promotes loose coupling, easier testing, and better maintainability by separating object creation from business logic.
There are three main types of dependency injection:
Constructor Injection: Dependencies are provided through the class constructor.
Setter Injection: Dependencies are provided using setter methods.
Field Injection: Dependencies are injected directly into fields (commonly used in frameworks like Spring).
Example (Constructor Injection):
1class Engine {
2 void start() {
3 System.out.println("Engine started");
4 }
5}
6
7class Car {
8 private Engine engine;
9
10 Car(Engine engine) { // Dependency injected
11 this.engine = engine;
12 }
13
14 void drive() {
15 engine.start();
16 System.out.println("Car is running");
17 }
18}
19
20public class Main {
21 public static void main(String[] args) {
22 Engine engine = new Engine();
23 Car car = new Car(engine);
24 car.drive();
25 }
26}9. What is the difference between equals() and hashCode()?
In Java, equals() and hashCode() are methods defined in the Object class and are primarily used in collections like HashMap and HashSet.
equals(): Compares two objects for logical equality. It returns true if the objects are considered equal based on their content.
hashCode(): Returns an integer value representing the object’s hash code. It is used by hash-based collections to determine the bucket location.
Contract Rule: If two objects are equal according to equals(), they must return the same hashCode(). However, two objects with the same hashCode() are not necessarily equal.
Example:
1class Person {
2 String name;
3
4 Person(String name) {
5 this.name = name;
6 }
7
8 @Override
9 public boolean equals(Object obj) {
10 if (this == obj) return true;
11 if (!(obj instanceof Person)) return false;
12 Person p = (Person) obj;
13 return name.equals(p.name);
14 }
15
16 @Override
17 public int hashCode() {
18 return name.hashCode();
19 }
20}
2110. What is concurrent collection?
Concurrent collections in Java are thread-safe collection classes designed to handle multiple threads accessing and modifying data simultaneously without causing data inconsistency. They are part of the java.util.concurrent package and provide better performance than traditional synchronized collections.
Unlike collections like Vector or Hashtable, concurrent collections use advanced locking mechanisms or non-blocking algorithms to improve scalability.
Common concurrent collections include ConcurrentHashMap, CopyOnWriteArrayList, and BlockingQueue.
11. What is thread pool and executor framework?
A Thread Pool is a collection of reusable worker threads that execute tasks. Instead of creating a new thread for each task, threads are reused, which improves performance and resource management.
The Executor Framework, introduced in Java 5, is part of the java.util.concurrent package and provides a higher-level API for managing threads. It separates task submission from thread management using interfaces like Executor, ExecutorService, and classes like Executors.
Example:
1import java.util.concurrent.*;
2
3public class Main {
4 public static void main(String[] args) {
5 ExecutorService executor = Executors.newFixedThreadPool(2);
6
7 executor.submit(() -> System.out.println("Task 1 executed"));
8 executor.submit(() -> System.out.println("Task 2 executed"));
9
10 executor.shutdown();
11 }
12}12. What are futures and callables?
Callable and Future are part of the java.util.concurrent package and are used for asynchronous task execution that can return results.
Callable: Similar to Runnable, but it can return a result and throw checked exceptions. It defines the
call()method.Future: Represents the result of an asynchronous computation. It provides methods like
get(),isDone(), andcancel()to manage task results.
Example:
1import java.util.concurrent.*;
2
3public class Main {
4 public static void main(String[] args) throws Exception {
5 ExecutorService executor = Executors.newSingleThreadExecutor();
6
7 Callable<Integer> task = () -> 10 + 20;
8 Future<Integer> future = executor.submit(task);
9
10 System.out.println(future.get()); // 30
11
12 executor.shutdown();
13 }
14}13. What is Java serialization and deserialization?
Serialization in Java is the process of converting an object into a byte stream so that it can be saved to a file, sent over a network, or stored in a database. Deserialization is the reverse process of converting the byte stream back into a Java object.
To make a class serializable, it must implement the Serializable interface from the java.io package. The JVM uses classes like ObjectOutputStream and ObjectInputStream to perform serialization and deserialization.
Example:
1import java.io.*;
2
3class Person implements Serializable {
4 String name;
5
6 Person(String name) {
7 this.name = name;
8 }
9}
10
11public class Main {
12 public static void main(String[] args) throws Exception {
13 Person p = new Person("Aman");
14
15 // Serialization
16 ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("person.ser"));
17 out.writeObject(p);
18 out.close();
19
20 // Deserialization
21 ObjectInputStream in = new ObjectInputStream(new FileInputStream("person.ser"));
22 Person obj = (Person) in.readObject();
23 in.close();
24
25 System.out.println(obj.name);
26 }
27}14. What is Java NIO (non-blocking IO)?
Java NIO (New Input/Output) is a powerful I/O API that was introduced in Java 1.4. It provides non-blocking, high-performance input/output operations. In traditional IO, threads are blocked until data is read or written. But in NIO, a single thread can handle multiple channels efficiently.
The main components of Java NIO are:
Buffer: Stores data to be read or written.
Channel: Represents an open connection to an entity such as a file or socket.
Selector: Enables a single thread to monitor multiple channels for events.
Java NIO is widely used in scalable server applications where handling many simultaneous connections efficiently is required.
15. What is the difference between File and FileChannel?
File and FileChannel are both used for file handling in Java, but they belong to different APIs and serve different purposes.
File: It is the part of the
java.iopackage. It represents file and directory pathnames and is mainly used for file metadata operations such as creating, deleting, renaming, and checking file properties.FileChannel: It is the part of the
java.nio.channelspackage. It is used for reading, writing, mapping, and manipulating file data using buffers and supports non-blocking and high-performance I/O operations.
Example:
1import java.io.*;
2import java.nio.*;
3import java.nio.channels.*;
4
5public class Main {
6 public static void main(String[] args) throws Exception {
7 File file = new File("test.txt");
8 file.createNewFile();
9
10 RandomAccessFile raf = new RandomAccessFile(file, "rw");
11 FileChannel channel = raf.getChannel();
12
13 ByteBuffer buffer = ByteBuffer.allocate(10);
14 buffer.put("Hello".getBytes());
15 buffer.flip();
16 channel.write(buffer);
17
18 channel.close();
19 raf.close();
20 }
21}16. How do you optimize Java applications?
Optimizing Java applications involves improving performance, memory usage, and scalability. The first step is always profiling the application using tools like JVisualVM or JProfiler to identify bottlenecks.
Use efficient data structures (e.g., choose ArrayList vs LinkedList appropriately).
Minimize object creation and reuse objects where possible.
Optimize loops and avoid unnecessary computations inside them.
Use multithreading and thread pools efficiently for concurrent tasks.
Tune JVM parameters such as heap size (-Xms, -Xmx) and garbage collection settings.
Proper profiling, efficient coding practices, and JVM tuning together help achieve optimal performance in Java applications.
17. What is class loading and class loader hierarchy?
Class loading in Java is the process of loading the class files (.class files) into memory at the time of execution of the Java Virtual Machine (JVM). When a class is first referred to, the JVM loads, links, and initializes it before executing it.
The class loading process has three main phases: Loading (reading bytecode into memory), Linking (verification, preparation, and resolution), and Initialization (executing static blocks and assigning static variables).
Java follows a parent delegation model in its class loader hierarchy, which includes:
Bootstrap ClassLoader: Loads core Java classes from the JDK (like java.lang).
Extension (Platform) ClassLoader: Loads classes from the extension libraries.
Application (System) ClassLoader: Loads classes from the application’s classpath.
The parent delegation mechanism ensures security and avoids duplicate class loading by delegating class loading requests to the parent class loader first.
18. Explain memory leaks in Java.
A memory leak in Java is when objects that are no longer needed are still referenced, thus preventing the Garbage Collector from freeing up the memory that these objects occupy. Even though Java has a garbage collector that automatically frees up memory, memory leaks can still occur if references to objects that are no longer needed are still held.
Some of the most common sources of memory leaks are static collections that hold references, resources that are not closed (such as database connections or streams), misuse of listeners, and caching objects.
Example:
1import java.util.*;
2
3public class Main {
4 static List<Object> list = new ArrayList<>();
5
6 public static void main(String[] args) {
7 while (true) {
8 list.add(new Object()); // Objects never removed
9 }
10 }
11}
12Proper resource management, removing unused references, and using profiling tools like VisualVM or JProfiler can help detect and prevent memory leaks.
Related Articles
React JS Interview Questions
Prepare for your React interview with the most asked questions for freshers and experienced developers. Covers hooks, lifecycle, performance optimization, and real-world scenarios.
FrontendJavaScript Interview Questions
Prepare for your next tech interview with the most asked JavaScript interview questions and answers. It includes basic to advanced concepts, coding problems, and real-world scenarios for freshers and experienced developers.