Tags: java, jvm, spring, multithreading, collections, hibernate
Level: intermediate
TL;DR: Core Java memory model, OOP design, concurrency essentials, and Spring framework fundamentals structured for technical interview screening.
Java applications execute on the JVM using bytecode for platform independence.
Heap memory holds objects; stack memory stores thread-local execution frames and primitives.
String objects are immutable and managed via the JVM String Constant Pool.
equals() defines object equivalence; hashCode() returns the memory bucket identifier.
Contracts dictate: equal objects must strictly have identical hashCode values.
HashMap utilizes buckets combining array lookups, linked lists, and balanced red-black trees.
volatile prevents CPU caching and instruction reordering across thread boundaries.
Checked exceptions require mandatory compile-time handling; runtime exceptions do not.
Interfaces provide behavioral contracts; abstract classes supply shared partial implementations and state.
Spring inversion of control manages object lifecycles via dependency injection.
Q: How does a HashMap resolve hash collisions internally?R: I rely on bucket index calculation via hash masking. Collisions chain elements into linked lists, transforming into red-black trees when exceeding 8 entries.
Q: What is the functional difference between fail-fast and fail-safe iterators?R: I use fail-fast iterators on standard collections to throw ConcurrentModificationException on concurrent writes, while fail-safe iterators safely traverse cloned arrays.
Q: How do you guarantee thread safety without manual lock acquisition?R: I use AtomicInteger or ConcurrentHashMap for lock-free CAS operations, or declare fields volatile when visibility alone suffices.
Q: What happens when an unhandled exception occurs inside a Spring @Transactional method?R: By default, the transaction rolls back for unchecked RuntimeException instances, but commits if a checked exception is thrown unless rollbackFor is set.
Overriding equals() without overriding hashCode(), breaking hashing lookups in HashSet and HashMap.
Modifying a collection directly while iterating over it instead of invoking Iterator.remove().
Relying on == for object reference equality instead of .equals() for value equivalence.
Neglecting to close database connections or stream resources, causing pool and descriptor exhaustion.
Calling a @Transactional method directly from within the same class, bypassing proxy interceptors.
// Safe singleton initialization via double-checked locking
public class DatabaseConnection {
private static volatile DatabaseConnection instance;
private DatabaseConnection() {}
public static DatabaseConnection getInstance() {
if (instance == null) {
synchronized (DatabaseConnection.class) {
if (instance == null) {
instance = new DatabaseConnection();
}
}
}
return instance;
}
}
Java
// CompletableFuture asynchronous pipeline
CompletableFuture.supplyAsync(() -> fetchUserData(userId))
.thenApply(this::enrichUserProfile)
.thenAccept(this::persistRecord)
.exceptionally(ex -> {
logError(ex);
return null;
});
[ ] Garbage collector nuances: G1 vs ZGC memory regions
[ ] Stream API terminal vs intermediate lazy evaluations
[ ] Spring bean lifecycles: BeanPostProcessor execution hooks
[x] Java Memory Model: happens-before relationship guarantees
[x] ACID transaction propagation behaviors in Spring JPA