The questions that come up most often, each with a sample answer you can adapt into your own words. Read them out loud until the explanation feels natural.
What is the difference between == and .equals()?
Fundamentals== compares references for objects (whether two variables point to the same object) and values for primitives. .equals() compares logical equality as defined by the class; the default Object.equals() is reference equality, but classes like String and Integer override it to compare contents. So for two distinct String objects with the same characters, == may be false while .equals() is true.
Explain the equals() and hashCode() contract.
IntermediateIf two objects are equal by equals(), they must return the same hashCode(). If you override equals() but not hashCode(), hash-based collections like HashMap and HashSet break: equal objects land in different buckets and lookups fail. The reverse is allowed (equal hash codes do not require equality), which is just a hash collision.
Why is String immutable in Java?
IntermediateString immutability enables safe sharing through the string pool, makes strings safe to use as HashMap keys (their hash never changes), and provides thread-safety for free since the value cannot be mutated. It also supports security: a string passed to a file path or network call cannot be changed by another thread after a check. The cost is that string concatenation in a loop creates garbage, which is why you use StringBuilder.
What is the difference between a checked and an unchecked exception?
IntermediateChecked exceptions extend Exception (but not RuntimeException) and must be either caught or declared with throws; the compiler enforces handling, for recoverable conditions like IOException. Unchecked exceptions extend RuntimeException and are not enforced by the compiler; they represent programming errors like NullPointerException or IllegalArgumentException. The guideline is checked for recoverable, unchecked for bugs.
How does garbage collection work in the JVM?
AdvancedThe JVM heap is split into generations: most objects are allocated in the young generation and die quickly (minor GC), and survivors are promoted to the old generation (major GC). Generational collection exploits the fact that most objects are short-lived. Modern collectors like G1 and ZGC partition the heap into regions and aim to bound pause times, trading some throughput for predictable latency.
What does the volatile keyword do?
Advancedvolatile guarantees visibility: a write to a volatile field is immediately visible to other threads, and reads always fetch from main memory rather than a cached copy. It also establishes a happens-before ordering that prevents certain instruction reorderings. It does not provide atomicity for compound actions like count++, so for that you use synchronized or an atomic class.
When would you choose ArrayList over LinkedList?
FundamentalsUse ArrayList for almost everything: it has O(1) random access and better cache locality, and amortised O(1) append. LinkedList only wins when you do frequent insertions or removals at the ends or via an iterator and rarely index, but in practice ArrayList usually outperforms it even there because of memory locality. Defaulting to ArrayList is the safe answer.
What is the difference between HashMap and ConcurrentHashMap?
AdvancedHashMap is not thread-safe; concurrent modification can corrupt its internal structure or cause infinite loops in older versions. ConcurrentHashMap is thread-safe and high-throughput: it locks only a portion of the map (lock striping / per-bin synchronisation) so multiple threads can update different segments in parallel, and reads are largely lock-free. Use ConcurrentHashMap instead of wrapping HashMap with Collections.synchronizedMap when you need concurrency.