Java is one of the most widely tested languages in software engineering interviews across FAANG companies, product companies, and IT services firms. Whether you are preparing for a backend engineering role at Amazon, a Java developer position at an IT services firm, or a senior engineer role at a product company, the interview tests a consistent set of topics: core language internals, object-oriented design, collections, concurrency, and Spring Boot for backend roles.
If you want to practice these questions with a real engineer before your actual interview, book a mock interview on Intervue.io. The rest of this guide gives you what you need to walk in prepared.
What a Java Interview Covers
Java interviews test across five main areas. The depth expected in each area scales with seniority.
Core Java and JVM internals, cover how Java actually works under the hood: memory model, garbage collection, class loading, object lifecycle, and the differences between stack and heap. These questions appear at all levels but go deeper at senior level where interviewers probe GC tuning and memory leak diagnosis.
Object-oriented design, covers the four pillars (encapsulation, inheritance, polymorphism, abstraction), SOLID principles, and the ability to apply these to real design problems. At senior level this extends to design patterns and low-level design problems.
Collections and data structures, cover the Java Collections Framework, the internal implementation of commonly used data structures, and when to choose each. HashMap internals, ArrayList vs LinkedList, and the thread-safe alternatives are high-frequency topics.
Concurrency and multithreading, is the area that trips up the most candidates. Thread lifecycle, synchronisation mechanisms, the Java Memory Model, deadlock prevention, and the java.util.concurrent package are all expected knowledge from mid-level upward.
Spring Boot and backend frameworks appear in most practical Java interviews for backend roles. Dependency injection, bean lifecycle, Spring MVC request handling, JPA and Hibernate basics, and REST API design are all standard.
Core Java Questions
What is the difference between == and .equals() in Java?
The == operator checks reference equality: it returns true only if both variables point to the exact same object in memory. The .equals() method checks value equality: it returns true if the objects are logically equivalent according to their .equals() implementation.
For String, Integer, and other wrapper classes, always use .equals() for value comparison. The == operator can produce unexpected results with these types because of how Java handles object interning and caching.
java
String a = new String("hello");
String b = new String("hello");
System.out.println(a == b); // false: different objects
System.out.println(a.equals(b)); // true: same value
What is the difference between final, finally, and finalize?
These three keywords serve completely different purposes and interviewers ask this specifically to confirm you understand each.
final is a keyword that makes a variable constant (cannot be reassigned), a method non-overridable, or a class non-extendable.
finally is a block in a try-catch-finally statement that always executes regardless of whether an exception was thrown or caught. It is used for cleanup operations like closing database connections or file streams.
finalize is a method in the Object class that was called by the garbage collector before reclaiming an object's memory. It is deprecated since Java 9 and should not be used in modern Java code.
How does HashMap work internally in Java?
HashMap stores key-value pairs in an array of buckets. When you call put(key, value), Java computes the hash code of the key, applies a bit manipulation to spread the distribution, and uses the result to determine the bucket index.
If two keys hash to the same bucket (a collision), they are stored as a linked list within that bucket. From Java 8 onward, when a bucket's linked list exceeds 8 entries and the total map size exceeds 64, the list converts to a balanced tree (red-black tree) for O(log n) lookup within the bucket instead of O(n).
The default initial capacity is 16 with a load factor of 0.75. When the number of entries exceeds capacity times load factor, the map resizes by doubling capacity and rehashing all existing entries.
Why this matters in interviews: interviewers ask this to see whether you understand the performance implications. HashMap operations are O(1) average but O(n) worst case when all keys collide into one bucket. Knowing about the tree conversion threshold signals production-level Java knowledge.
What is the difference between ArrayList and LinkedList?
ArrayList is backed by a dynamic array. Random access by index is O(1). Insertion and deletion in the middle are O(n) because elements need to be shifted. It is the right choice when you primarily read by index.
LinkedList is a doubly linked list. Insertion and deletion at the head or tail are O(1). Random access by index is O(n) because you must traverse from the head. It is the right choice when you primarily insert or delete at the ends.
In practice, ArrayList outperforms LinkedList for almost all real-world use cases because of cache locality: array elements are stored contiguously in memory, making iteration significantly faster than pointer-chasing through a linked list.
What is the Java Memory Model and what does volatile do?
The Java Memory Model defines how threads interact through memory. Each thread has its own working memory, a cache of main memory. Without proper synchronisation, a thread may read a stale value from its cache rather than the latest value from main memory.
The volatile keyword tells the JVM that a variable's value must always be read from and written to main memory directly, never from a thread's local cache. This guarantees visibility: when one thread writes to a volatile variable, all other threads immediately see the updated value.
volatile does not guarantee atomicity. For compound operations like incrementing a counter (read, increment, write), you still need synchronisation or an atomic class like AtomicInteger.
Concurrency Questions
What is a deadlock and how do you prevent it?
A deadlock occurs when two or more threads are each waiting for a resource held by the other, creating a circular dependency where none can proceed.
Classic example: Thread A holds Lock 1 and waits for Lock 2. Thread B holds Lock 2 and waits for Lock 1. Neither can proceed.
Prevention strategies: always acquire locks in a consistent global order across all threads, use tryLock() with a timeout instead of blocking indefinitely, minimise the scope of synchronisation blocks, and use higher-level concurrency utilities from java.util.concurrent instead of low-level synchronisation where possible.
What is the difference between synchronized and ReentrantLock?
synchronized is the simpler, built-in Java mechanism for mutual exclusion. It automatically releases the lock when the block exits, even if an exception is thrown. It does not support timeout, interruptibility, or fairness policies.
ReentrantLock from java.util.concurrent.locks provides the same mutual exclusion but with additional features: tryLock() with a timeout so a thread does not wait forever, lockInterruptibly() so a waiting thread can be interrupted, and a fairness mode that grants the lock to the longest-waiting thread.
ReentrantLock requires explicit unlock() in a finally block. Forgetting to unlock is a common bug. For simple use cases, synchronized is cleaner. For scenarios requiring timeout or interrupt support, ReentrantLock is the right tool.
What is the difference between Callable and Runnable?
Runnable represents a task that executes and returns nothing. Its run() method has no return value and cannot declare a checked exception.
Callable represents a task that executes and returns a result. Its call() method returns a typed value and can declare checked exceptions.
Callable is used with ExecutorService.submit(), which returns a Future that can be used to retrieve the result, check completion status, or cancel the task.
java
Callable<Integer> task = () -> {
return 42;
};
Future<Integer> future = executor.submit(task);
int result = future.get(); // blocks until result is ready
Object-Oriented Design Questions
What are the SOLID principles?
Single Responsibility: a class should have one reason to change. A UserService that handles user business logic should not also handle email sending. Split into UserService and EmailService.
Open/Closed: classes should be open for extension and closed for modification. Instead of adding if-else conditions to a payment processor for each new payment type, define a PaymentMethod interface and implement a new class for each payment type.
Liskov Substitution: subclasses should be substitutable for their parent class without changing the program's correctness. If a method accepts a Shape, it should work correctly with Circle, Rectangle, or any other Shape subclass.
Interface Segregation: clients should not be forced to implement interfaces they do not use. Instead of one large Printer interface with print, scan, fax, and staple methods, create separate interfaces so simple printers only implement print.
Dependency Inversion: high-level modules should depend on abstractions, not concrete implementations. Instead of OrderService directly instantiating MySQLOrderRepository, inject an OrderRepository interface so the implementation can be swapped without changing OrderService.
Spring Boot Questions
What is dependency injection and how does Spring implement it?
Dependency injection is a design pattern where an object's dependencies are provided externally rather than created internally. This makes the object easier to test and decouples it from specific implementations.
Spring implements dependency injection through its IoC (Inversion of Control) container. You declare beans and their dependencies. Spring creates the beans, resolves the dependency graph, and injects dependencies at runtime.
The three injection styles: constructor injection (recommended because it makes dependencies explicit and allows immutability), setter injection (for optional dependencies), and field injection using @Autowired (convenient but makes testing harder because dependencies cannot be set without Spring).
What happens when a Spring Boot application starts?
Spring Boot starts by loading the main class annotated with @SpringBootApplication, which is a composite of @Configuration, @EnableAutoConfiguration, and @ComponentScan.
Auto-configuration scans the classpath for libraries present and automatically configures beans based on what it finds. If spring-data-jpa is on the classpath, it auto-configures a DataSource, EntityManagerFactory, and transaction manager.
@ComponentScan scans the package of the main class and all sub-packages for @Component, @Service, @Repository, and @Controller annotations, instantiates those classes as beans, and registers them in the application context.
The embedded server (Tomcat by default) is then started and the application begins serving requests.
What Interviewers Actually Score in a Java Interview
Most candidates prepare answers to individual questions. What interviewers are actually evaluating is different.
They score depth of understanding: can you explain not just what something does but how it works internally and why it was designed that way. Knowing that HashMap uses a linked list for collisions is surface knowledge. Knowing why it converts to a red-black tree at 8 entries and what the performance implication was before this change is the depth that earns strong signals at mid-level and above.
They score applied reasoning: can you connect the concept to a real problem. "You said to use volatile for visibility. In what specific scenario would you choose volatile over synchronised and why?"
They score production awareness: do you know the failure modes. "What happens to your HashMap when two threads call put() simultaneously without synchronisation?" The answer is data corruption due to race conditions during resize, not just "it is not thread-safe."
How to Prepare for a Java Mock Interview
Answering questions correctly in a quiet room is different from performing under real interview conditions. In a live Java interview, you are explaining internals while the interviewer watches, handling follow-up questions that probe your reasoning, and writing code in a plain editor without IDE support.
The topics most candidates are under-prepared on: concurrency and multithreading. Most candidates know the basics of synchronised and volatile but cannot reason about the Java Memory Model, explain happens-before relationships, or design a thread-safe class from scratch. If you are targeting mid-level or above, concurrency is the area to invest in most.
For Spring Boot, dependency injection and the bean lifecycle are the two highest-frequency topics. Know them well enough to trace through what happens at startup and what happens when two beans have a circular dependency.
FAQs
Is Java accepted for FAANG coding rounds? Yes. Java is widely accepted at Amazon, Google, Meta, and Apple for software engineering coding rounds. Amazon in particular has a large Java-based backend and many candidates choose Java for their coding rounds.
What Java version should I prepare for? Know Java 8 features deeply: lambdas, streams, Optional, and functional interfaces. Be aware of Java 11 and Java 17 LTS additions. Interviewers rarely ask version-specific trivia but modern features like records, sealed classes, and virtual threads can come up in senior interviews.
Is Spring Boot required for Java interviews? For backend engineering roles, yes. Core Spring concepts including dependency injection, bean lifecycle, Spring MVC, and JPA basics are expected from mid-level upward. For pure algorithmic coding rounds, Spring Boot is not tested.
What is the most commonly missed Java interview topic? Concurrency. Most candidates know the basics but cannot reason about the Java Memory Model or design a thread-safe class from scratch. This is the gap that most often separates mid-level passes from rejections.




