Java Collections — Interview Questions & Answers
Q1. What is the Internal Working of ArrayList?
ArrayList is a resizable array implementation of the List interface.
Internally, it uses an array to store elements:
ArrayList
↓
Object[]
[10] [20] [30] [40] [ ] [ ] ...When the array becomes full, ArrayList creates a larger array and copies the existing elements into it.
Important points:
- Allows duplicate elements.
- Maintains insertion order.
- Allows
null. - Provides fast random access using index: O(1).
- Adding at the end is usually O(1) amortized.
- Inserting/removing from the middle is O(n) because elements need to be shifted.
- It is not thread-safe.
Example:
List<Integer> list = new ArrayList<>();
list.add(10);
list.add(20);
list.add(30);Q2. What is the Internal Working of HashMap?
HashMap stores data as key-value pairs.
Map<String, Integer> map = new HashMap<>();
map.put("Java", 100);Internally, it uses an array of buckets. When we insert a key, its hashCode() is used to calculate a bucket location.
Conceptually:
Key
↓
hashCode()
↓
Hash calculation
↓
Bucket
↓
Key-Value EntryIf multiple keys map to the same bucket, a collision occurs. Java handles collisions using linked structures, and in modern Java, a heavily-collided bucket can be converted into a Red-Black Tree.
When retrieving:
map.get("Java");HashMap calculates the hash again, finds the bucket, and compares keys using equals() to locate the correct entry.
Average complexity:
put() → O(1)
get() → O(1)
remove() → O(1)These are average cases; collisions can affect performance.
Important: HashMap allows one null key and multiple null values and is not thread-safe.
Q3. ConcurrentHashMap vs Hashtable
Both are thread-safe maps, but their concurrency mechanisms are different.
Hashtable
Hashtable is a legacy collection. Its main methods are synchronized, meaning access is heavily serialized.
Hashtable<Integer, String> table = new Hashtable<>();ConcurrentHashMap
ConcurrentHashMap was designed for high-concurrency applications
ConcurrentHashMap<Integer, String> map =
new ConcurrentHashMap<>();It allows multiple threads to operate on different parts of the map concurrently and uses modern synchronization/atomic mechanisms internally.
| Hashtable | ConcurrentHashMap |
| --------------------------------- | ---------------------------------- |
| Legacy | Modern |
| Synchronized methods | Fine-grained concurrency |
| Lower concurrency | Higher concurrency |
| Does not allow `null` key/value | Does not allow `null` key/value |
| Generally slower under contention | Better for concurrent applications |Q4. Vector vs ArrayList
Don’t choose Vector simply because it is synchronized. For concurrent use, choose a collection based on the actual concurrency requirements.
Both are dynamic arrays, but they differ mainly in thread safety.
Vector
Vector is a legacy collection whose major methods are synchronized.
ArrayList
ArrayList is not synchronized and is therefore generally faster in single-threaded scenarios.
| Vector | ArrayList |
| ------------------------------------- | ---------------- |
| Legacy | Modern |
| Synchronized | Not synchronized |
| Thread-safe for individual operations | Not thread-safe |
| Generally slower | Generally faster |
| Dynamic array | Dynamic array |Q5. LinkedList vs ArrayList
Don’t assume LinkedList is automatically faster for insertions. If you first need to traverse to the insertion position, that traversal itself can be O(n). In most everyday application code, ArrayList is the better default.
Both implementList, but their internal structures are different.
ArrayList
Uses a dynamic array.
[10] [20] [30] [40]Provides fast index-based access:
list.get(2);Time complexity: O(1).
LinkedList
Uses a doubly linked list.
10 ↔ 20 ↔ 30 ↔ 40Accessing an element by index requires traversal, so:
list.get(30);is O(n).
| ArrayList | LinkedList |
| ----------------------------- | ---------------------------------------------- |
| Dynamic array | Doubly linked list |
| `get()` → O(1) | `get()` → O(n) |
| Better cache locality | More pointer overhead |
| Usually better default choice | Useful for specific insertion/removal patterns |Q6. TreeMap vs HashMap
Use HashMap when you primarily need fast lookup; use TreeMap when you need keys maintained in sorted order or need navigational operations.
HashMap
Uses hashing and provides average O(1) lookup.
Map<Integer, String> map = new HashMap<>();It does not maintain sorted key order.
TreeMap
Uses a Red-Black Tree and keeps keys sorted.
Map<Integer, String> map = new TreeMap<>();Operations such as put(), get(), and remove() generally take O(log n).
| HashMap | TreeMap |
| ------------------- | ----------------------------------------------------- |
| Hash table | Red-Black Tree |
| Average O(1) | O(log n) |
| No sorted order | Sorted by keys |
| Allows one null key | Null keys generally not allowed with natural ordering |
| Faster lookup | Useful when sorted order is required |Q7. What are Immutable Classes?
An immutable object cannot be modified after it is created.
Get Anuj Singh’s stories in your inbox
Join Medium for free to get updates from this writer.
The most common example is String.
String name = "Java";
name.concat(" Programming");
System.out.println(name); // Javaconcat() does not modify the original String; it creates a new object.
How to create an immutable class?
Typically:
- Make the class
final. - Make fields
privateandfinal. - Initialize fields through the constructor.
- Don’t provide setters.
- Don’t expose mutable internal objects directly.
- Return defensive copies when necessary.
Example:
final class Employee {
private final String name;
Employee(String name) {
this.name = name;
}
public String getName() {
return name;
}
}Q8. Shallow Copy vs Deep Copy
Shallow Copy
A shallow copy creates a new outer object but references the same nested objects.
Original ──→ Address
Copy ───┘So modifying the nested object through one copy can affect the other.
Deep Copy
A deep copy creates a new outer object and copies the nested objects as well.
Original → Address A
Copy → Address BChanges to one object’s nested state don’t affect the other.
Example:
Employee e1 = ...;
Employee e2 = shallowCopy(e1);Both may point to the same Address.
With deep copying:
Employee e2 = deepCopy(e1);e2 gets its own Address.
Q9. Comparator vs Comparable
Use Comparable when the class has a clear natural order; use Comparator when sorting requirements can vary.
Both are used for sorting objects.
Comparable
Used when a class defines its natural ordering.
class Employee implements Comparable<Employee> {
private int age;
@Override
public int compareTo(Employee other) {
return Integer.compare(this.age, other.age);
}
}Then:
Collections.sort(employees);Comparator
Used when we want to define sorting outside the class or need multiple sorting strategies.
employees.sort(
Comparator.comparing(Employee::getName)
);| Comparable | Comparator |
| ---------------------------- | ------------------------------------ |
| `compareTo()` | `compare()` |
| Defines natural ordering | Defines custom ordering |
| Implemented by the class | Separate object/interface |
| Usually one natural ordering | Multiple sorting strategies possible |Q10. What is CopyOnWriteArrayList?
CopyOnWriteArrayList is a thread-safe List implementation designed for scenarios with many reads and very few writes.
When a modification occurs, it creates a new copy of the underlying array.
Before write:
Readers → [A B C]
Write
After write:
Readers → [A B C]
Writer → [A B C D]Readers can continue reading without being blocked by the writer.
Advantages:
- Thread-safe
- Excellent for read-heavy workloads
- Iterators don’t throw
ConcurrentModificationExceptiondue to concurrent modifications
Disadvantage:
- Every write creates a new array, making writes expensive.
- Can consume significant memory for large lists.
Typical use cases include configuration data or listener lists that are read frequently but modified rarely.
Q11. What is WeakHashMap and What are References?
WeakHashMap is useful when you don't want the map itself to prevent its keys from being garbage collected.
WeakHashMap stores keys using weak references.
If a key is no longer strongly referenced elsewhere, the Garbage Collector can remove that key from the map.
Map<Key, Value> map = new WeakHashMap<>();Conceptually:
Strong Reference
↓
Key
↓
WeakHashMapIf the strong reference disappears:
Strong Reference → removed
↓
Key
↓
GC can collect it
↓
WeakHashMap entry disappearsThis can be useful for certain caches or metadata where entries should not keep keys alive.
Reference types
Java provides different reference strengths:
- Strong Reference — normal reference; object remains reachable.
- Soft Reference — may be collected when memory is needed.
- Weak Reference — can be collected when no strong references remain.
- Phantom Reference — used for advanced lifecycle/cleanup mechanisms.
Q12. What is ConcurrentModificationException?
ConcurrentModificationException generally occurs when a collection is structurally modified while it is being iterated, except through the iterator's own supported modification operation.
Example:
List<Integer> numbers =
new ArrayList<>(Arrays.asList(1, 2, 3));
for (Integer n : numbers) {
if (n == 2) {
numbers.remove(n);
}
}This can throw:
ConcurrentModificationExceptionThe common reason is that the collection detects that it has been structurally modified after the iterator was created.
Correct approach
Use the iterator:
Iterator<Integer> iterator = numbers.iterator();
while (iterator.hasNext()) {
if (iterator.next() == 2) {
iterator.remove();
}
}Or use appropriate collection APIs:
numbers.removeIf(n -> n == 2);Important: The name can be misleading. ConcurrentModificationException does not necessarily mean multiple threads are involved. It can happen in a single thread when a collection is modified during iteration.
Also, this behavior is generally fail-fast, not a synchronization guarantee. It is intended to detect bugs early, not to provide thread safety.
These are some of the most frequently asked Java Collections interview questions. If you liked this article, do give it a 👏 Clap!






