Java (Core) β 30 Interview Questions (Answers & Examples)¶
Cover the answer, then say it aloud in 3β7 sentences with a tiny snippet. Bold words are what the interviewer is listening for.
Q1. What are the main features of Java?¶
Java is a platform-independent, object-oriented, automatically memory-managed language that compiles source to bytecode run by the JVM.
In plain words: you write once and run anywhere because the JVM sits between your code and the OS. The headline features interviewers want are platform independence ("write once, run anywhere" via bytecode), object-oriented, automatic garbage collection, robust (strong typing, exception handling), multithreaded, and secure (no raw pointers, bytecode verification). It's also portable and has a huge standard library.
public class Hello {
public static void main(String[] args) {
System.out.println("Write once, run anywhere");
}
}
Q2. What is the difference between JDK, JRE, and JVM?¶
The JVM runs bytecode, the JRE = JVM + core libraries to run apps, and the JDK = JRE + compiler and developer tools.
In plain words: JVM executes, JRE lets you run, JDK lets you build. If you only run a .jar you need the JRE; if you compile .java you need the JDK.
| Component | What it is | Contains |
|---|---|---|
| JVM | Runtime engine that executes bytecode | Class loader, bytecode verifier, JIT, GC |
| JRE | Environment to run Java apps | JVM + core class libraries |
| JDK | Kit to develop Java apps | JRE + javac, jar, javadoc, debugger |
javac Hello.java # JDK: compile .java -> Hello.class (bytecode)
java Hello # JRE/JVM: load + execute the bytecode
Q3. What are the OOP principles in Java?¶
The four OOP pillars are Encapsulation, Inheritance, Polymorphism, and Abstraction.
In plain words: Encapsulation hides data behind methods (private fields + getters/setters); Inheritance lets a class reuse another via extends; Polymorphism lets one interface take many forms (overriding/overloading); Abstraction exposes what an object does while hiding how. Together they make code modular, reusable, and easier to change.
class Animal { void sound() { System.out.println("..."); } } // Abstraction/base
class Dog extends Animal { // Inheritance
private String name; // Encapsulation
@Override void sound() { System.out.println("Woof"); } // Polymorphism
}
Animal a = new Dog(); a.sound(); // Woof (runtime polymorphism)
Q4. What is the difference between == and .equals() in Java?¶
== compares references (or values for primitives), while .equals() compares logical content.
In plain words: for objects, == asks "same memory address?" and .equals() asks "same value?". For primitives there's no .equals(), and == compares the actual value.
| Operator | Compares | For objects |
|---|---|---|
== |
Reference identity (value for primitives) | Are they the same object? |
.equals() |
Content/logical equality | Do they mean the same? |
String a = new String("hi");
String b = new String("hi");
System.out.println(a == b); // false (different objects)
System.out.println(a.equals(b)); // true (same content)
Remember: == = same box, .equals() = same stuff inside. Override equals() and hashCode() together.
Q5. What is the difference between ArrayList and LinkedList?¶
ArrayList is a resizable array giving O(1) random access, while LinkedList is a doubly linked list giving O(1) insert/delete at the ends.
In plain words: pick ArrayList when you mostly read/index by position; pick LinkedList when you insert/remove a lot at the front or back.
| Aspect | ArrayList | LinkedList |
|---|---|---|
| Backing store | Dynamic array | Doubly linked nodes |
Random access get(i) |
O(1) | O(n) |
| Insert/delete at end | Amortized O(1) | O(1) |
| Insert/delete at front/middle | O(n) (must shift) | O(1) at ends; O(n) to reach the middle |
| Memory | Compact | Extra per-node pointers |
List<Integer> al = new ArrayList<>(); // fast get(i)
List<Integer> ll = new LinkedList<>(); // fast addFirst/addLast
Q6. What is the difference between HashMap, LinkedHashMap, and TreeMap?¶
HashMap is unordered, LinkedHashMap preserves insertion order, and TreeMap keeps keys sorted.
In plain words: same key/value API, different iteration order and cost.
| Map | Order | Lookup | Null keys |
|---|---|---|---|
| HashMap | None (bucket order) | O(1) avg | One null key |
| LinkedHashMap | Insertion order | O(1) avg | One null key |
| TreeMap | Sorted by key (Comparable/Comparator) | O(log n) | No null key |
Map<String,Integer> h = new HashMap<>(); // unordered
Map<String,Integer> l = new LinkedHashMap<>(); // keeps insert order
Map<String,Integer> t = new TreeMap<>(); // sorted keys
Q7. What is a constructor in Java? How is it different from a method?¶
A constructor is a special block invoked when an object is created to initialize it; it has the class name and no return type.
In plain words: a constructor sets up a new object; a method defines behavior you call later. Constructors are called automatically via new, can't be static/final/abstract, and if you write none Java supplies a default no-arg one.
class User {
String name;
User(String name) { this.name = name; } // constructor: no return type
void greet() { System.out.println("Hi " + name); } // method
}
new User("Ana").greet();
Q8. What is method overloading and method overriding?¶
Overloading is same method name with different parameter lists in the same class (compile-time); overriding is a subclass redefining an inherited method with the same signature (runtime).
In plain words: overloading = more ways to call the same idea; overriding = a child changing the behavior it inherited.
class Calc {
int add(int a, int b) { return a + b; } // overload
double add(double a, double b) { return a + b; } // overload
}
class Base { void run() { System.out.println("base"); } }
class Child extends Base { @Override void run() { System.out.println("child"); } } // override
Q9. What is the difference between abstract class and interface?¶
An abstract class can hold state and partial implementation and supports single inheritance; an interface defines a contract and supports multiple inheritance of type.
In plain words: use an abstract class for an "is-a" base with shared code/fields; use an interface for a capability many unrelated classes can implement.
| Aspect | Abstract class | Interface |
|---|---|---|
| Inheritance | Single (extends) |
Multiple (implements) |
| State/fields | Instance fields allowed | Only public static final constants |
| Methods | Abstract + concrete | Abstract, default, static (Java 8+) |
| Constructor | Yes | No |
abstract class Shape { abstract double area(); double describe(){ return area(); } }
interface Drawable { void draw(); default void hint(){ System.out.println("draw me"); } }
Q10. What is the difference between final, finally, and finalize()?¶
final is a modifier that prevents change, finally is a block that always runs after try/catch, and finalize() was a method the GC called before reclaiming an object.
In plain words: three unrelated things that sound alike.
| Keyword | Kind | Purpose |
|---|---|---|
final |
Modifier | Constant var, non-overridable method, non-subclassable class |
finally |
Block | Cleanup that always executes |
finalize() |
Method | Pre-GC hook (deprecated; avoid) |
final int MAX = 10; // cannot reassign
try { risky(); }
catch (Exception e) { log(e); }
finally { System.out.println("always runs"); }
Remember: final = can't change, finally = always runs, finalize() = GC's goodbye (don't rely on it).
Q11. What is a static variable and static method in Java?¶
static members belong to the class itself, not to any instance, so they're shared across all objects and callable without an object.
In plain words: a static variable is one shared copy for the whole class (like a counter); a static method runs without an instance and can only touch static state directly.
class Counter {
static int count = 0; // shared across all instances
Counter() { count++; }
static int total() { return count; } // call as Counter.total()
}
new Counter(); new Counter();
System.out.println(Counter.total()); // 2
Q12. What are access modifiers in Java?¶
Access modifiers control the visibility of classes, fields, and methods: private, default (package-private), protected, and public.
In plain words: they set who can see a member β same class only, same package, package + subclasses, or everyone.
| Modifier | Same class | Same package | Subclass | World |
|---|---|---|---|---|
private |
yes | no | no | no |
| default | yes | yes | no | no |
protected |
yes | yes | yes | no |
public |
yes | yes | yes | yes |
public class Account {
private double balance; // hidden
protected String owner; // package + subclasses
public double getBalance(){ return balance; }
}
Q13. What is the difference between String, StringBuilder, and StringBuffer?¶
String is immutable, StringBuilder is a mutable non-synchronized builder, and StringBuffer is a mutable thread-safe (synchronized) builder.
In plain words: use String for fixed text, StringBuilder for building/looping in one thread, StringBuffer when multiple threads share the builder.
| Type | Mutable | Thread-safe | Speed |
|---|---|---|---|
String |
No | Yes (immutable) | Slow for concat in loops |
StringBuilder |
Yes | No | Fastest |
StringBuffer |
Yes | Yes (synchronized) | Slower than StringBuilder |
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 3; i++) sb.append(i);
System.out.println(sb); // 012 (no new String each iteration)
Remember: String is immutable β every "change" makes a new object; loop-concatenation should use StringBuilder.
Q14. What is exception handling in Java? Explain try-catch-finally.¶
Exception handling lets you deal with runtime errors gracefully using try (risky code), catch (handle the exception), and finally (always-run cleanup).
In plain words: wrap the dangerous code in try, react in catch, and free resources in finally no matter what. This keeps the program from crashing and separates error-handling from normal logic.
try {
int x = 10 / 0; // throws ArithmeticException
} catch (ArithmeticException e) {
System.out.println("Handled: " + e.getMessage());
} finally {
System.out.println("Cleanup always runs");
}
Q15. What is the difference between checked and unchecked exceptions?¶
Checked exceptions are verified at compile time and must be declared or handled; unchecked exceptions extend RuntimeException and occur at runtime.
In plain words: the compiler forces you to deal with checked ones (like file/IO), but trusts you with unchecked ones (usually programming bugs).
| Type | When | Examples | Compiler forces handling |
|---|---|---|---|
| Checked | Compile time | IOException, SQLException |
Yes |
| Unchecked | Runtime | NullPointerException, ArithmeticException |
No |
void read() throws IOException { // checked: must declare/handle
Files.readString(Path.of("f.txt"));
}
String s = null; s.length(); // unchecked: NullPointerException
Remember: Checked = compiler-checked (IOException); unchecked = runtime bug (NullPointerException).
Q16. What is the use of throw and throws keywords?¶
throw actually raises an exception object, while throws declares in a method signature which checked exceptions it may propagate.
In plain words: throw is the action of throwing; throws is the warning label on the method saying "callers, beware."
// throws: propagate a CHECKED exception (caller must handle/declare)
void readConfig(String path) throws IOException { // declares
if (!new File(path).exists()) throw new IOException("Missing: " + path); // raises
}
// throw alone: raise an UNCHECKED exception for a bad argument (no throws needed)
void validate(int age) {
if (age < 18) throw new IllegalArgumentException("Too young"); // raises
}
Note: use
IllegalArgumentException(unchecked) for bad inputs β notIllegalAccessException, which is a reflection exception meaning "reflective access was denied."
Q17. What is a collection in Java?¶
A collection is an object that groups multiple elements into a single unit, and the Collections Framework provides interfaces (List, Set, Queue, Map) and implementations to store and manipulate them.
In plain words: instead of juggling arrays by hand, the framework gives you ready-made, resizable, algorithm-rich data structures with a common API. Core interfaces are Collection (List/Set/Queue) and Map, backed by classes like ArrayList, HashSet, and HashMap.
List<String> names = new ArrayList<>();
names.add("Ana"); names.add("Bob");
Collections.sort(names); // framework utilities
Q18. What is the difference between Set, List, and Map interfaces?¶
List is an ordered collection allowing duplicates, Set is an unordered collection of unique elements, and Map stores keyβvalue pairs with unique keys.
In plain words: List = indexed sequence with duplicates, Set = no duplicates, Map = dictionary of keyβvalue.
| Interface | Duplicates | Order | Access |
|---|---|---|---|
| List | Allowed | Insertion order, indexed | By index |
| Set | Not allowed | Depends on impl | By value/contains |
| Map | Unique keys | Depends on impl | By key |
List<Integer> list = new ArrayList<>(List.of(1,1,2)); // [1,1,2]
Set<Integer> set = new HashSet<>(List.of(1,1,2)); // [1,2]
Map<String,Integer> map = Map.of("a",1,"b",2); // a->1, b->2
Q19. What are Generics in Java?¶
Generics let you parameterize types so classes and methods work with a specified type while giving compile-time type safety and removing casts.
In plain words: List<String> guarantees only Strings go in and come out, so the compiler catches type errors early instead of failing at runtime with a ClassCastException.
List<String> names = new ArrayList<>(); // only Strings
names.add("Ana");
String first = names.get(0); // no cast needed
<T> T firstOf(List<T> items) { return items.get(0); } // generic method
Q20. What is multithreading in Java?¶
Multithreading is running multiple threads concurrently within one process to use CPU efficiently and perform tasks in parallel.
In plain words: threads are lightweight units of execution that share the process's memory, so you can do work like I/O and computation at the same time. You create them by extending Thread or implementing Runnable (preferred), then call start().
Runnable task = () -> System.out.println("Running on " + Thread.currentThread().getName());
Thread t = new Thread(task);
t.start(); // runs concurrently with main
Q21. What is the difference between synchronized block and method?¶
A synchronized method locks the whole method on one object (or class for static), while a synchronized block locks only a chosen region on a specified lock object for finer control.
In plain words: the block is more granular and lets you pick the lock, reducing the critical section and improving concurrency.
| Aspect | Synchronized method | Synchronized block |
|---|---|---|
| Scope of lock | Entire method | Only the enclosed statements |
| Lock object | this (or class for static) |
Any object you specify |
| Granularity | Coarse | Fine (less contention) |
synchronized void inc() { count++; } // whole method locked on this
void inc2() {
synchronized (lock) { count++; } // only this region locked
}
Q22. What is the purpose of the volatile keyword?¶
volatile guarantees that reads and writes of a variable go straight to main memory, ensuring visibility of changes across threads.
In plain words: without it, a thread may cache a variable and never see another thread's update; volatile forces every access to be fresh. It ensures visibility (and ordering) but does NOT make compound actions like count++ atomic β use AtomicInteger or synchronized for that.
class Worker {
private volatile boolean running = true; // visible to all threads
void stop() { running = false; } // other thread sees it immediately
void run() { while (running) { /* work */ } }
}
Q23. What is a lambda expression in Java 8?¶
A lambda is a concise, anonymous function that implements a functional interface, written as (params) -> body.
In plain words: it lets you pass behavior as data without writing a full anonymous class, making code shorter and more readable. Lambdas power the Streams and functional-programming features of Java 8+.
Runnable r = () -> System.out.println("Hello lambda");
List<String> list = List.of("b", "a", "c");
list.stream().sorted((x, y) -> x.compareTo(y)).forEach(System.out::println);
Q24. What are functional interfaces?¶
A functional interface has exactly one abstract method, making it a target type for lambdas and method references; it's often annotated @FunctionalInterface.
In plain words: one abstract method means one clear behavior a lambda can supply. Common built-ins are Runnable, Comparator, Function, Predicate, Supplier, and Consumer.
@FunctionalInterface
interface Greeting { String message(String name); }
Greeting g = name -> "Hi " + name; // lambda supplies the single method
System.out.println(g.message("Ana")); // Hi Ana
Q25. What is the Stream API in Java 8?¶
The Stream API processes sequences of elements with a declarative, functional pipeline of intermediate operations (map, filter) and a terminal operation (collect, forEach).
In plain words: instead of writing loops, you describe what to do β filter, transform, reduce β and streams handle the iteration, supporting lazy evaluation and easy parallelism. Intermediate ops are lazy; nothing runs until a terminal op is called.
List<Integer> nums = List.of(1, 2, 3, 4, 5);
List<Integer> evensDoubled = nums.stream()
.filter(n -> n % 2 == 0) // intermediate
.map(n -> n * 2) // intermediate
.collect(Collectors.toList()); // terminal -> [4, 8]
Q26. What is the difference between Iterator and ListIterator?¶
Iterator traverses any Collection forward-only, while ListIterator works on Lists and traverses both forward and backward with add/set support.
In plain words: ListIterator is a more powerful, List-specific cursor.
| Aspect | Iterator | ListIterator |
|---|---|---|
| Applies to | Any Collection | List only |
| Direction | Forward only | Forward + backward |
| Modify | remove() |
remove(), add(), set() |
| Index | No | nextIndex(), previousIndex() |
List<String> list = new ArrayList<>(List.of("a", "b"));
ListIterator<String> it = list.listIterator();
while (it.hasNext()) { it.next(); it.set("x"); } // replace while iterating
Q27. How does garbage collection work in Java?¶
Garbage collection automatically reclaims heap memory from objects that are no longer reachable from any live reference.
In plain words: the JVM tracks which objects can still be reached; unreachable ones are eligible for GC, freeing you from manual free(). Modern collectors use a generational heap (young/old), collecting short-lived objects cheaply in the young generation. You can suggest a run with System.gc(), but the JVM decides when.
Object obj = new Object();
obj = null; // no more references -> eligible for garbage collection
// JVM reclaims it later; timing is not guaranteed
Q28. How do you handle file operations in Java?¶
File operations use classes like File, java.nio.file.Files/Path, and streams/readers to create, read, write, and delete files, ideally with try-with-resources for auto-close.
In plain words: modern Java favors the NIO Files and Path API for concise reading/writing, and try-with-resources ensures streams close even on error. This maps directly to test automation β reading config, test data, or writing reports.
Path path = Path.of("data.txt");
Files.writeString(path, "hello"); // write
String content = Files.readString(path); // read
try (BufferedReader br = Files.newBufferedReader(path)) {
System.out.println(br.readLine()); // auto-closed
}
Q29. How do you use Java to send an HTTP request?¶
Since Java 11 you use the built-in java.net.http.HttpClient to build a request and send it synchronously or asynchronously.
In plain words: create an HttpClient, build an HttpRequest with URI/method/headers, send it, and read the HttpResponse. For API test automation, teams often layer RestAssured on top, but core Java has a first-class client now.
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/users"))
.GET()
.build();
HttpResponse<String> resp = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.statusCode() + " " + resp.body());
Q30. How is Java used in Selenium or any automation framework?¶
In Selenium, Java is the binding (client) language: you use the Java WebDriver API to drive a browser, combine it with TestNG/JUnit for test structure, and build a Page Object framework around it.
In plain words: Selenium exposes Java classes like WebDriver and WebElement; you write Java to locate elements, perform actions, and assert results. Java's OOP (Page Objects), collections (test data), exception handling (waits/failures), and libraries (TestNG, RestAssured, Maven) make it the backbone of a robust automation framework.
WebDriver driver = new ChromeDriver();
driver.get("https://example.com/login");
driver.findElement(By.id("username")).sendKeys("ana");
driver.findElement(By.id("password")).sendKeys("secret");
driver.findElement(By.cssSelector("button[type='submit']")).click();
Assert.assertEquals(driver.getTitle(), "Dashboard"); // TestNG assertion
driver.quit();