So, before we start, let me ask you something. How many of you have applied, or are planning to apply, to a big tech company? Google, Amazon, Meta, Microsoft, Netflix, any of these?
I'm guessing quite a few of you have your hands up mentally. Now let me ask a follow-up. How many of you feel truly confident walking into a Java interview for one of these companies?
Fewer, right? That's completely normal. And that's exactly why I'm here today. I'm going to walk you through fifteen questions, real, FAANG-style Java questions, that show up again and again in interviews. But I'm not just going to give you answers to cram. I'm going to explain each one the way I'd explain it to a friend, in plain language, with examples, so that it actually sticks in your head. Because in these interviews, understanding beats memorizing every single time.
Let's get started.
1. What is the difference between == and .equals() in Java?
Okay, this is almost always the first question you'll hear. It sounds simple, but so many students get it wrong, so let's slow down.
Think of == as asking, "Are these two things literally the exact same box?" And think of .equals() as asking, "Do these two boxes contain the same stuff inside?"
Let me show you what I mean.
String a = new String("hello");
String b = new String("hello");
System.out.println(a == b); // false
System.out.println(a.equals(b)); // true
Here, a and b both say "hello". But when we use new String(...), Java creates two completely separate boxes in memory, even though both boxes have the same word written inside them. So a == b is false, because they are not the same box. But a.equals(b) is true, because when you open both boxes, the content matches.
So remember this simple rule: == compares memory addresses, .equals() compares actual values. Whenever you're comparing objects like Strings, or your own custom classes, always prefer .equals(), not ==.
2. What is the difference between String, StringBuilder, and StringBuffer?
This question is really testing two things: do you understand immutability, and do you understand thread safety. Let me explain both with a simple example.
Imagine String is like a printed photograph. Once it's printed, you cannot change it. If you want a "modified" version, you have to print a brand-new photo.
String s = "Hello";
s = s + " World";
It looks like we changed s, right? But actually, Java threw away the old "Hello" photo and printed a brand new photo called "Hello World". The original never changed. That's what "immutable" means.
Now, StringBuilder is like a whiteboard. You can erase and rewrite on the same whiteboard again and again, without creating a new one each time.
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World"); // same object, just updated
This is much faster when you're doing lots of changes, like building a long string inside a loop.
Then what's StringBuffer? It's basically the same whiteboard, but now imagine multiple people are allowed to write on it at the same time, from different threads. StringBuffer has built-in locks so that two threads don't scribble over each other's writing at the same moment. StringBuilder does not have these locks, so it's faster, but only safe to use with a single thread.
So here's your simple decision rule: normal text, use String. Lots of changes, single thread, use StringBuilder. Lots of changes, multiple threads, use StringBuffer.
3. What is the difference between an abstract class and an interface?
This used to be a simple question, but after Java 8, it got a bit trickier, because interfaces can now have method bodies too, using something called default methods. So don't just say "interfaces can't have code inside them", that's outdated, and interviewers will catch it immediately.
Let's use an everyday example. Think of an abstract class like a half-built house. It already has a foundation, some walls, maybe a roof, some parts are done, but you still need to add a few things before you can move in.
abstract class Vehicle {
String brand = "Generic"; // this is state, actual data
abstract void drive(); // this part is unfinished, you must complete it
}
Now think of an interface like a checklist or a contract. It doesn't give you a house at all. It just tells you, "If you want to call yourself a Vehicle, you must be able to drive, you must be able to stop." It doesn't care how you do it, or what materials you use.
interface Drivable {
void drive(); // just a promise, no actual house behind it
}
The key difference students often miss: an abstract class can hold actual data, actual state, like brand in my example. An interface, even with default methods, still can't hold instance state like that. And in Java, a class can implement many interfaces, because promises are cheap, you can make as many promises as you like. But a class can only extend one abstract class, because you can only inherit one half-built house.
If they ask you "why can't Java have multiple class inheritance", mention the diamond problem, if two parent classes had a method with the same name, the compiler wouldn't know which one to use. Interfaces avoid this confusion.
4. How does HashMap work internally?
This is a favorite everywhere, Google, Amazon, Microsoft, all of them ask some version of this. They don't want to hear "it stores key-value pairs", they already know that. They want to see if you understand what's happening under the hood.
Let me explain it like a locker room. Imagine a HashMap is a big wall of lockers. When you want to store something with a certain key, Java doesn't randomly pick a locker. Instead, it runs your key through a formula, called hashCode(), and that formula tells it exactly which locker number to use.
map.put("apple", 10);
Java calculates a hash code for "apple", does a bit of extra mixing to spread things out evenly, and figures out, "okay, this goes in locker number 7."
Now here's the interesting part. Sometimes two completely different keys can end up pointing to the same locker number. That's called a collision. What happens then? Since Java 8, if a locker gets more than 8 items crammed into it, Java is smart enough to convert that locker from a simple list into a red-black tree, which makes searching through it much faster, especially if that locker gets really crowded.
One more thing worth mentioning to really impress the interviewer: HashMap has something called a load factor, which is 0.75 by default. This means once your HashMap is 75% full, Java automatically doubles its size and redistributes everything, to keep lookups fast. If you mention load factor and resizing, you'll stand out from most candidates.
5. What is the difference between throw and throws?
This one's short, but under interview pressure, people still mix these up, so let's nail it with a clear example.
Think of throw as the actual action of throwing a ball. It happens inside your code, at a specific moment, when something goes wrong.
throw new IOException("File not found");
Now think of throws as a warning label on a box, telling people in advance, "hey, this box might contain something dangerous, be careful when you open it." It appears in the method signature, not inside the method body.
public void readFile() throws IOException {
if (fileMissing) {
throw new IOException("File not found");
}
}
So throws is a declaration, a warning to whoever calls your method. throw is the actual event of throwing the exception. Simple as that.
6. What are checked and unchecked exceptions?
Let's continue with the same idea of warning labels. A checked exception is something Java forces you to deal with, right there at compile time. If you don't handle it or declare it, your code won't even compile. Examples are IOException and SQLException, things like a missing file or a broken database connection, situations you can reasonably expect and recover from.
An unchecked exception is different. Java doesn't force you to handle these at compile time. These usually happen because of a programming mistake, like NullPointerException or ArrayIndexOutOfBoundsException. Think about it, if you access index 10 of an array that only has 5 elements, that's a bug in your logic, not something you were expected to "recover" from gracefully.
If the interviewer asks, "When would you design your own exception as checked versus unchecked?", here's a good way to answer: use checked exceptions for things a caller can reasonably recover from, like a file not being found, and use unchecked exceptions for programming errors that should be fixed in the code itself, not handled at runtime.
7. Explain the Java Memory Model, Stack versus Heap.
This tests whether you actually understand what's happening when your program runs, not just how to write syntax.
Picture the stack like a stack of trays in a cafeteria. Every time you call a method, Java places a new tray on top, containing that method's local variables. When the method finishes, that tray gets removed instantly. It's fast, organized, and each thread has its own separate stack of trays.
void greet() {
String name = "Alex"; // lives on the stack, in this method's tray
}
The heap, on the other hand, is like a big shared warehouse. This is where actual objects live, things created with new, and it's shared across your entire application, across all threads. Unlike the stack, items in the heap don't disappear automatically the moment a method ends. They stick around until the garbage collector decides nothing is using them anymore, and clears them out.
A common follow-up question: "Where does a String literal live?" The answer is, in a special section of the heap called the String Pool. Java keeps a pool of commonly used strings so that if you write "hello" in two different places in your code, Java can reuse the same object instead of creating duplicates, saving memory.
8. What is the difference between final, finally, and finalize()?
This is a classic wordplay question, three words that sound similar but do completely different jobs. Let's separate them clearly.
final is a keyword you use to say "this cannot be changed." If you mark a variable final, its value can't be reassigned. If you mark a method final, no subclass can override it. If you mark a class final, nobody can extend it.
final int MAX_USERS = 100; // this value can never change
finally is a block of code that always runs after a try-catch, no matter what happens, whether an exception was thrown or not. It's typically used for cleanup, like closing a file or a database connection.
try {
// risky code
} finally {
// this always runs, success or failure
}
finalize() is a method that used to be called by the garbage collector right before it destroyed an object, sort of like a "last chance" cleanup method. But here's an important detail most students miss: finalize() is deprecated since Java 9. Modern Java code prefers using try-with-resources or the Cleaner class instead. If you mention that it's deprecated, you immediately signal to the interviewer that you're working with current knowledge, not outdated textbook material.
9. How does garbage collection work in Java?
Big topic, so let's simplify it with an analogy. Imagine your heap is like a college hostel room, and objects are like students living there temporarily.
Most students, when they join, don't stay very long, they finish their short course and check out quickly. Java calls this area the Young Generation, and it has two parts, Eden, where new objects are born, and Survivor spaces, where objects that stick around a bit longer get moved.
1. New objects go into Eden.
2. Most die quickly and get cleared, this is called Minor GC.
3. Objects that survive several rounds get promoted to the Old Generation.
4. Major or Full GC cleans the Old Generation, but it's more expensive and slower.
Java assumes, correctly most of the time, that most objects die young, this is called the weak generational hypothesis, and it's the whole reason garbage collection is designed this way, so it can quickly clean up short-lived objects without scanning the entire heap every time.
You don't need to memorize every garbage collector by name, but it helps to know that Java gives you choices, like G1, ZGC, and Shenandoah, and each one makes a different trade-off between how fast your program runs and how long it pauses during cleanup.
10. What is multithreading, and how do you create a thread in Java?
Multithreading simply means your program can do multiple things at the same time, instead of doing one task, finishing it completely, then moving to the next. Think of it like a restaurant kitchen where multiple chefs are cooking different dishes simultaneously, instead of one chef cooking everything one dish at a time.
There are two common ways to create a thread in Java. Let me show you both.
// Way 1: extending the Thread class
class MyThread extends Thread {
public void run() {
System.out.println("Running");
}
}
// Way 2: implementing the Runnable interface
class MyTask implements Runnable {
public void run() {
System.out.println("Running");
}
}
Now, which one should you use, and why? Here's the key insight. If you extend Thread, you've used up your one and only chance to extend a class in Java, remember, a class can only extend one other class. But if you implement Runnable, your class is still free to extend something else if needed, because interfaces don't use up that one inheritance slot. That's exactly why most experienced developers prefer Runnable, it keeps your design more flexible.
11. What is the difference between synchronized methods and synchronized blocks?
When multiple threads try to access shared data at the same time, things can get messy, like two people trying to write on the same page simultaneously. synchronized is Java's way of saying "only one thread can be in here at a time."
A synchronized method locks the entire method. If it's an instance method, it locks on the current object, this. If it's a static method, it locks on the entire class.
public synchronized void increment() {
count++;
}
But here's the problem, this locks the whole method, even parts that don't actually need protection, which can slow things down unnecessarily.
A synchronized block is more precise, it only locks the specific lines of code that actually need protection, and you choose exactly which object to lock on.
public void increment() {
synchronized (lockObject) {
count++;
}
}
So the takeaway here is simple: synchronized blocks give you finer control, and by locking only what's necessary, you reduce the chances of threads waiting around unnecessarily, which improves performance.
12. What are Comparable and Comparator?
Both of these help you sort objects, but they solve the problem in different ways. Let me explain with an example.
Imagine you have a Student class. Comparable is like giving that class its own built-in, natural way of sorting itself, usually by something like roll number.
class Student implements Comparable<Student> {
int rollNumber;
public int compareTo(Student other) {
return this.rollNumber - other.rollNumber;
}
}
Now, what if sometimes you want to sort by roll number, but other times you want to sort by marks, or by name? You don't want to keep changing the Student class every time your sorting needs change. That's exactly where Comparator comes in, it's a completely separate class that defines a custom way of sorting, without touching the original class at all.
class MarksComparator implements Comparator<Student> {
public int compare(Student a, Student b) {
return a.marks - b.marks;
}
}
So, simple rule to remember: Comparable defines one natural, default sorting order, written inside the class itself. Comparator lets you define as many custom sorting orders as you like, completely outside the class.
13. What is the difference between ArrayList and LinkedList?
Think of ArrayList like a row of numbered seats in a movie theater. If I ask you, "what's in seat number 15?", you can walk straight there instantly. That's fast random access. But if I ask you to add a new seat right in the middle of the row, everyone after that seat has to shift over, which takes time.
ArrayList<Integer> list = new ArrayList<>();
list.get(15); // instant, direct access
LinkedList, on the other hand, is like a treasure hunt, where each clue tells you where to find the next one. If I ask you what's at position 15, you have to start from the beginning and follow the chain step by step to get there, which is slower. But if I want to insert something in the middle, I just need to change a couple of connections, no shifting required.
LinkedList<Integer> list = new LinkedList<>();
list.addFirst(5); // fast insertion at the ends
In real-world code, ArrayList is used far more often, because most programs read data more often than they insert into the middle. But it's worth knowing when LinkedList shines, like when you're building a queue or a deque, where you're constantly adding and removing from the ends.
14. Can you explain the SOLID principles with a Java example?
FAANG companies ask this because they don't just want someone who can write code that works, they want someone who can write code that's easy to maintain and extend later. Let's go through each letter quickly, with a simple example tying them together.
S, Single Responsibility, a class should have only one reason to change. Don't make one class handle both "calculating salary" and "sending emails", split those into separate classes.
O, Open for extension, closed for modification. You should be able to add new behavior without rewriting existing, tested code.
L, Liskov Substitution, if Dog extends Animal, then anywhere your code expects an Animal, a Dog object should work perfectly fine too, without breaking anything.
I, Interface Segregation, don't force a class to implement methods it doesn't actually need. Better to have several small, focused interfaces than one giant one.
D, Dependency Inversion, your code should depend on abstractions, not on specific implementations.
Here's a simple example tying it together, a PaymentProcessor interface, with CreditCardPayment and PaypalPayment as separate implementations. If tomorrow you need to add UpiPayment, you just create a new class, you don't touch any existing code. That's Open/Closed and Dependency Inversion working together in one clean example.
15. Design a parking lot system using Object-Oriented principles.
This is the big one, a low-level design question. Companies like Amazon and Google love asking this, because it tests everything at once, abstraction, encapsulation, relationships between classes, and how you think about real-world problems.
Here's how I'd suggest you approach it, step by step, out loud, in the interview.
First, identify your entities, the "nouns" in your problem. Here, that's things like ParkingLot, ParkingSpot, Vehicle, Ticket, and PaymentProcessor.
Second, figure out the relationships between them. Does a ParkingLot contain multiple ParkingSpot objects? Yes, that's composition. Does Vehicle have different types, like Car and Bike? Yes, that's inheritance.
Third, think about behavior. How does a car actually get assigned to a spot? What happens if the lot is completely full? How does a ticket get generated when a car enters, and how is payment handled when it exits?
Fourth, only now, write some skeleton code, just class names and key method signatures, not a fully finished, working program. Interviewers want to see clear structure and reasoning, not perfect syntax typed out in fifteen minutes.
The single biggest mistake students make here is jumping straight into typing code the moment they hear the question. Don't do that. Talk through your entities and relationships out loud first, sketch it on the whiteboard if you can. Interviewers are grading how you think, not how fast you can type.
Before I wrap up
Let me leave you with three things that matter far more than memorizing any single answer.
First, don't memorize answers word for word. Interviewers can always tell, and the moment they twist the question slightly, a memorized answer falls apart. Understand the "why" behind each concept, so you can adapt on the spot.
Second, always think out loud during the interview. A wrong answer explained with clear, logical reasoning often scores better than a correct answer given in silence, because interviewers are evaluating how you think, not just what you know.
Third, practice explaining these concepts to someone else, a friend, a classmate, even your own reflection in the mirror. If you can teach a concept clearly and simply, that's real proof you actually understand it.
These fifteen questions won't guarantee you a job offer. Nothing can guarantee that. But they will make sure you're never caught off guard on Java fundamentals, and that gives you the confidence to focus on what really matters in these interviews, solving the actual problem sitting in front of you.
Alright, that's it from me today. Any questions?
