All Java Interview Questions
What is encapsulation in Java?
Encapsulation is hiding the data of a class and allowing access only through methods. You make the fields private and write public getters and setters, which can check the values.
class Account {
private double balance;
public double getBalance() { return balance; }
public void deposit(double amount) {
if (amount <= 0) throw new IllegalArgumentException("Amount must be positive");
balance += amount;
}
}
public class Main {
public static void main(String[] args) {
Account a = new Account();
a.deposit(500);
System.out.println(a.getBalance());
}
}
500.0
What are the access modifiers in Java?
| Modifier | Same class | Same package | Subclass | Other packages |
|---|---|---|---|---|
| private | yes | no | no | no |
| default (no word) | yes | yes | no | no |
| protected | yes | yes | yes | no |
| public | yes | yes | yes | yes |
Use the most restricted level which works. Fields are usually private, and the methods which others must use are public. See Encapsulation.
What is the difference between an array and an ArrayList in Java?
| Point | Array | ArrayList |
|---|---|---|
| Size | Fixed | Dynamic |
| Types | Primitives and objects | Objects only (use wrappers) |
| Length | arr.length | list.size() |
| Add or remove | Not possible | add(), remove() |
| Generics | No | Yes |
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
int[] arr = new int[3];
List<Integer> list = new ArrayList<>();
list.add(10);
list.add(20);
System.out.println(arr.length + " " + list.size());
}
}
3 2
See Java Arrays and Java ArrayList.
Why is the main method public static void in Java?
The JVM starts a program by calling public static void main(String[] args).
- public: the JVM is outside your class, so the method must be visible.
- static: the JVM calls it before any object exists.
- void: it does not return a value to the JVM.
- String[] args: the command line arguments.
Since Java 25 you can write a short form for small programs, with no class and no public static:
void main() {
IO.println("Hello from a compact source file");
}
Hello from a compact source file
What is garbage collection in Java?
In Java you create objects with new but you never delete them. The garbage collector of the JVM finds the objects that no variable can reach anymore, and frees their memory.
public class Main {
public static void main(String[] args) {
Object o = new Object();
o = null; // now nothing points to the first object
System.gc(); // only a request; the JVM decides
System.out.println("Done");
}
}
Done
- You can not force garbage collection.
System.gc()is only a hint. - Memory leaks can still happen, for example when a static list keeps growing.
What is a package in Java?
A package groups related classes and interfaces, like folders group files. The first line of the file is package com.shop; and the folder must be com/shop. Packages avoid name clashes and give package level access.
java.langis imported automatically (String,Math).- Other packages need an
import, likeimport java.util.List;.
See Java Packages and Imports for a tested example with javac -d.
What is an exception in Java? What are checked and unchecked exceptions?
An exception is an event which stops the normal flow of the program. Java gives an object of the exception, and you can catch it with try and catch.
| Type | Must handle? | Example |
|---|---|---|
| Checked | Yes, the compiler forces it | IOException, SQLException |
| Unchecked (RuntimeException) | No | NullPointerException, ArithmeticException |
| Error | No, do not catch | OutOfMemoryError |
public class Main {
public static void main(String[] args) {
try {
System.out.println(10 / 0);
} catch (ArithmeticException e) {
System.out.println("Caught: " + e.getMessage());
} finally {
System.out.println("finally runs always");
}
}
}
Caught: / by zero
finally runs always
See Java Exceptions.
What are autoboxing and unboxing in Java?
Each primitive has a wrapper class: int – Integer, double – Double, boolean – Boolean. Java converts between them by itself:
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
Integer boxed = 5; // autoboxing
int plain = boxed; // unboxing
List<Integer> list = new ArrayList<>();
list.add(10); // autoboxing
int first = list.get(0); // unboxing
System.out.println(boxed + plain + first);
Integer a = 127, b = 127, c = 1000, d = 1000;
System.out.println(a == b); // true: small values are cached
System.out.println(c == d); // false: different objects
System.out.println(c.equals(d));
}
}
20
true
false
true
Compare wrapper objects with equals(), not with ==. Unboxing a null gives a NullPointerException.
What is a JAR file in Java and how to create one?
A JAR (Java ARchive) file is a ZIP file which holds compiled .class files, resources and a manifest. It is the normal way to share a Java library or an application.
public class Hello {
public static void main(String[] args) {
System.out.println("Running from a JAR");
}
}
$ javac Hello.java
$ jar cfe app.jar Hello Hello.class
$ java -jar app.jar
Running from a JAR
$ jar tf app.jar
META-INF/
META-INF/MANIFEST.MF
Hello.class
ccreate,ffile name,eentry point (the class withmain).jar tflists the content of a JAR.
Real projects use Maven or Gradle to build the JAR.
How does HashMap work internally in Java?
A HashMap is an array of buckets. When you call put(key, value):
- Java calls
key.hashCode()and spreads the bits of the hash. - The bucket index is found from the hash and the array length (the default size is 16).
- If the bucket is empty, the entry is stored there. If not, Java walks the bucket and uses
equals()to find the same key. If it finds one, the value is replaced, if not the new entry is added. - When the number of entries goes above capacity x load factor (0.75), the array is doubled and the entries are moved (rehashing).
- When one bucket gets long (8 or more entries, and the table has 64 or more buckets), the linked list becomes a balanced tree, so the search stays fast.
So the keys need a good hashCode() and a matching equals(). Even with a very bad hash code the map still gives right answers, only slow:
import java.util.HashMap;
import java.util.Map;
public class Main {
static class BadKey {
final int id;
BadKey(int id) { this.id = id; }
@Override public int hashCode() { return 1; } // all keys in one bucket
@Override public boolean equals(Object o) { return o instanceof BadKey b && b.id == id; }
}
public static void main(String[] args) {
Map<BadKey, String> map = new HashMap<>();
for (int i = 0; i < 1000; i++) {
map.put(new BadKey(i), "value" + i);
}
System.out.println(map.size());
System.out.println(map.get(new BadKey(777)));
}
}
1000
value777
See Java HashMap.
What is the difference between HashMap, Hashtable and ConcurrentHashMap?
| Point | HashMap | Hashtable | ConcurrentHashMap |
|---|---|---|---|
| Thread safe | No | Yes (locks the whole table) | Yes (fine grained locks) |
| Null key | One allowed | Not allowed | Not allowed |
| Null values | Allowed | Not allowed | Not allowed |
| Speed | Fastest (one thread) | Slow | Fast with many threads |
| Use | Normal code | Old code only | Shared data between threads |
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class Main {
static void tryNull(String name, Map<String, String> map) {
try {
map.put(null, "x");
System.out.println(name + ": null key allowed");
} catch (NullPointerException e) {
System.out.println(name + ": null key NOT allowed");
}
}
public static void main(String[] args) {
tryNull("HashMap", new HashMap<>());
tryNull("Hashtable", new Hashtable<>());
tryNull("ConcurrentHashMap", new ConcurrentHashMap<>());
}
}
HashMap: null key allowed
Hashtable: null key NOT allowed
ConcurrentHashMap: null key NOT allowed
Why must you override both equals() and hashCode() in Java?
The contract: equal objects must have the same hash code. If you override equals() but not hashCode(), two equal objects get different hash codes, and a HashSet keeps both:
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
public class Main {
static class Bad {
final String name;
Bad(String name) { this.name = name; }
@Override public boolean equals(Object o) { return o instanceof Bad b && b.name.equals(name); }
}
static class Good {
final String name;
Good(String name) { this.name = name; }
@Override public boolean equals(Object o) { return o instanceof Good g && g.name.equals(name); }
@Override public int hashCode() { return Objects.hash(name); }
}
public static void main(String[] args) {
Set<Bad> bad = new HashSet<>();
bad.add(new Bad("Riya"));
bad.add(new Bad("Riya"));
System.out.println("Without hashCode: " + bad.size()); // wrong: 2
Set<Good> good = new HashSet<>();
good.add(new Good("Riya"));
good.add(new Good("Riya"));
System.out.println("With hashCode: " + good.size()); // right: 1
}
}
Without hashCode: 2
With hashCode: 1
The easy way: use a record, which writes both methods for you (Java Records).
How to create an immutable class in Java?
- Declare the class
final(no subclass can break it). - Make all fields
private final. - Do not write setters.
- Set all fields in the constructor.
- For mutable fields (like a list or a date) make a defensive copy when you get it and when you return it.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Main {
static final class Team {
private final String name;
private final List<String> members;
Team(String name, List<String> members) {
this.name = name;
this.members = List.copyOf(members); // copy in
}
String name() { return name; }
List<String> members() { return members; } // List.copyOf is already unmodifiable
}
public static void main(String[] args) {
List<String> list = new ArrayList<>(List.of("Riya", "Aman"));
Team t = new Team("Java", list);
list.add("Hacker"); // does not change the team
System.out.println(t.members());
try {
t.members().add("Another");
} catch (UnsupportedOperationException e) {
System.out.println("Cannot change the members");
}
}
}
[Riya, Aman]
Cannot change the members
A record is the shortest way, if you only need the data and you copy the mutable parts yourself. See Java Records.
What is the difference between final, finally and finalize in Java?
| Name | Kind | Meaning |
|---|---|---|
| final | Keyword | A constant variable, a method which can not be overridden, a class which can not be extended |
| finally | Block | Runs after try and catch, with or without an exception. For cleaning |
| finalize() | Method | Called by the GC before it removes an object. Deprecated for removal, do not use it |
Use try with resources or a Cleaner instead of finalize().
public class Main {
static int test() {
try {
return 1;
} finally {
System.out.println("finally runs, even after return");
}
}
public static void main(String[] args) {
final int limit = 10;
System.out.println(limit + " " + test());
}
}
finally runs, even after return
10 1
See Java Exceptions.
What is the difference between stack and heap memory in Java?
| Point | Stack | Heap |
|---|---|---|
| Keeps | Method calls, local variables, references | Objects and arrays |
| Per | One stack for each thread | One heap shared by all threads |
| Cleaned | When the method ends | By the garbage collector |
| Size | Small | Big |
| Error when full | StackOverflowError | OutOfMemoryError |
public class Main {
static void recurse(int n) {
recurse(n + 1);
}
public static void main(String[] args) {
int local = 5; // on the stack
String s = new String("object"); // the object is on the heap, the reference s on the stack
try {
recurse(1);
} catch (StackOverflowError e) {
System.out.println("Stack is full: StackOverflowError");
}
System.out.println(local + " " + s);
}
}
Stack is full: StackOverflowError
5 object
Size options: -Xss for the stack and -Xmx for the maximum heap. See Java Recursion.
What is the string pool in Java and what does intern() do?
Equal string literals share one object from the string pool. A string made with new is a separate object on the heap. intern() returns the pooled version.
public class Main {
public static void main(String[] args) {
String a = "java";
String b = "java";
String c = new String("java");
String d = c.intern();
System.out.println(a == b); // same pooled object
System.out.println(a == c); // c is a different object
System.out.println(a == d); // intern gives the pooled one
System.out.println("ja" + "va" == a); // joined at compile time: pooled
}
}
true
false
true
true
Always compare content with equals(). See Java Strings.
What is the difference between Comparable and Comparator in Java?
| Point | Comparable | Comparator |
|---|---|---|
| Package | java.lang | java.util |
| Method | compareTo(T other) | compare(T a, T b) |
| Where | Inside the class | A separate object or lambda |
| Orders | One natural order | Many orders |
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class Main {
record Student(String name, int marks) implements Comparable<Student> {
@Override
public int compareTo(Student other) {
return this.name.compareTo(other.name); // natural order: by name
}
}
public static void main(String[] args) {
List<Student> list = new ArrayList<>(List.of(new Student("Meera", 95), new Student("Aman", 72), new Student("Riya", 88)));
java.util.Collections.sort(list); // uses compareTo
System.out.println(list);
list.sort(Comparator.comparingInt(Student::marks).reversed()); // another order
System.out.println(list);
}
}
[Student[name=Aman, marks=72], Student[name=Meera, marks=95], Student[name=Riya, marks=88]]
[Student[name=Meera, marks=95], Student[name=Riya, marks=88], Student[name=Aman, marks=72]]
What is the difference between ArrayList and LinkedList in Java?
| Point | ArrayList | LinkedList |
|---|---|---|
| Inside | Resizable array | Doubly linked nodes |
| Get by index | Fast, O(1) | Slow, O(n) |
| Add at the end | Fast (usually) | Fast |
| Add or remove at the start | Slow, O(n) | Fast, O(1) |
| Memory | Less | More (each node has two links) |
| Also a Deque | No | Yes |
In practice ArrayList is the better choice for almost all cases, because of its simple memory layout. For a queue or a stack use ArrayDeque. See Java HashSet and LinkedList.
What is the difference between fail-fast and fail-safe iterators?
Fail-fast iterators (ArrayList, HashMap) check a modification counter and throw ConcurrentModificationException when the collection is changed in the loop. Fail-safe (weakly consistent) iterators, like those of CopyOnWriteArrayList and ConcurrentHashMap, do not throw.
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class Main {
public static void main(String[] args) {
List<Integer> failFast = new ArrayList<>(List.of(1, 2, 3, 4));
try {
for (Integer n : failFast) {
if (n == 1) failFast.add(99);
}
} catch (java.util.ConcurrentModificationException e) {
System.out.println("ArrayList: ConcurrentModificationException");
}
List<Integer> failSafe = new CopyOnWriteArrayList<>(List.of(1, 2, 3, 4));
for (Integer n : failSafe) {
if (n == 1) failSafe.add(99);
}
System.out.println("CopyOnWriteArrayList: " + failSafe);
}
}
ArrayList: ConcurrentModificationException
CopyOnWriteArrayList: [1, 2, 3, 4, 99]
To remove items while looping, use removeIf() or the remove() of the iterator.
What is type erasure in Java generics?
Generics are checked by the compiler, and then the type arguments are erased. At run time a List<String> is only a List. This keeps old code working, but it has effects:
- You can not write
new T(),T.classorinstanceof List<String>. - You can not make an array of a generic type:
new List<String>[10]. - Primitives are not allowed as type arguments.
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> strings = new ArrayList<>();
List<Integer> numbers = new ArrayList<>();
System.out.println(strings.getClass() == numbers.getClass());
System.out.println(strings.getClass().getName());
}
}
true
java.util.ArrayList
See Java Generics.
- « Previous
- 1
- 2
- 3
- Next »