← All courses

Interview questionsSoftware EngineeringBeginner

Top 10 Java and OOP interview questions

OOP pillars, HashMap internals, equals and hashCode, String immutability, exceptions, JVM memory and threads: the Java questions campus and lateral interviews ask most, answered precisely.

10 min · 10 questions

1What are the four pillars of OOP? Explain each with an example.

  • Encapsulation: keep data private and expose controlled methods. A BankAccount has a private balance and a deposit() method that rejects negative amounts.
  • Abstraction: expose what an object does, hide how. A PaymentGateway interface with pay(order); the caller doesn't know whether it uses UPI or cards.
  • Inheritance: a class reuses and extends another (Intern extends Employee), modelling an "is-a" relationship.
  • Polymorphism: the same call behaves differently depending on the object. employee.monthlyPay() returns salary/12 for a FullTime employee and the stipend for an Intern. Compile-time polymorphism is overloading; runtime polymorphism is overriding with dynamic dispatch.

Tie each to a benefit: encapsulation protects invariants, abstraction reduces coupling, inheritance reuses code, polymorphism lets you add new types without changing callers.

2What is the difference between an abstract class and an interface?

  • An abstract class can have state (fields), constructors, and both abstract and concrete methods. A class can extend only one.
  • An interface defines a contract. It has abstract methods plus default and static methods (Java 8+) and private methods (Java 9+), but no instance state or constructors. A class can implement many.

Use an abstract class when closely related classes share code and state (Employee → FullTime, Intern). Use an interface for a capability that unrelated classes can have (Comparable, Serializable, PaymentGateway). Modern guidance: prefer interfaces, and composition over inheritance.

3How does HashMap work internally?

  • Internally it's an array of buckets. On put(k, v), Java computes k.hashCode(), spreads the bits, and picks the bucket with hash & (n - 1).
  • If the bucket is empty, the entry goes in. If not (a collision), it walks the entries: if one equals the key, its value is replaced; otherwise the new entry is appended.
  • Since Java 8, a bucket with more than 8 entries (and a table of at least 64) turns into a red-black tree, making the worst case O(log n).
  • When the number of entries exceeds capacity × load factor (default 16 × 0.75 = 12), the table doubles and entries are redistributed.
  • get uses the same hash to find the bucket and equals to find the entry: O(1) on average.

It allows one null key and many null values, isn't synchronized, and doesn't keep order (use LinkedHashMap for insertion order and TreeMap for sorted keys).

4Why must you override hashCode when you override equals?

The contract: if a.equals(b) then a.hashCode() == b.hashCode(). Hash-based collections find the bucket by hashCode first and only then compare with equals.

If you override only equals, two logically equal objects usually get different hash codes (the default is identity-based), land in different buckets, and:

java
Set<Point> set = new HashSet<>();
set.add(new Point(1, 2));
set.contains(new Point(1, 2));   // false without a matching hashCode

Duplicates sneak into sets and map lookups fail. Fix: override both using the same fields (Objects.hash(x, y)), or use a record, which generates them.

5Why is String immutable in Java? String vs StringBuilder vs StringBuffer?

String is immutable for:

  • Security: strings hold file paths, URLs and credentials; they can't be changed after validation.
  • String pool: identical literals share one object safely, saving memory.
  • Thread safety: immutable objects can be shared freely.
  • Hash caching: the hash code is computed once, which makes strings fast HashMap keys.

Comparison:

  • String: immutable; each concatenation in a loop creates new objects.
  • StringBuilder: mutable, not synchronized, fastest; use for building strings in a single thread.
  • StringBuffer: mutable and synchronized (thread-safe), slower; rarely needed today.

6What is the difference between == and equals()?

  • == compares references for objects (are these the same object in memory?) and values for primitives.
  • equals() compares logical content, as defined by the class. String, Integer and records override it to compare values; Object's default equals is the same as ==.
java
String a = "hire";
String b = "hire";
String c = new String("hire");
a == b        // true: both point to the pooled literal
a == c        // false: c is a new object
a.equals(c)   // true: same characters

Also watch Integer caching: Integer x = 100, y = 100; x == y is true (cached −128..127) but with 1000 it's false. Always compare wrapper objects with equals.

7Explain checked vs unchecked exceptions, and how you handle them.

  • Checked exceptions (subclasses of Exception but not RuntimeException, e.g. IOException, SQLException) represent recoverable conditions outside the program's control. The compiler forces you to catch them or declare them with throws.
  • Unchecked exceptions (RuntimeException subclasses such as NullPointerException, IllegalArgumentException, ArrayIndexOutOfBoundsException) usually indicate programming errors and don't need to be declared.
  • Errors (OutOfMemoryError, StackOverflowError) are serious JVM problems you generally don't catch.

Good practice: catch the specific exception you can handle; use try-with-resources to close resources; wrap low-level exceptions with context (keep the cause); never swallow exceptions silently; and don't use exceptions for normal control flow. In Spring, translate exceptions into HTTP responses with @ControllerAdvice.

8Explain JVM memory: stack vs heap, and garbage collection.

  • Stack: one per thread. Stores method call frames with local primitives and object references. Memory is freed automatically when a method returns. Too-deep recursion causes StackOverflowError.
  • Heap: shared by all threads. Stores all objects and arrays. Managed by the garbage collector, which frees objects no longer reachable from GC roots (thread stacks, static fields).
  • Other areas: Metaspace (class metadata), the code cache, and PC registers.

GC is generational: most objects die young, so new objects go into the Young generation (collected often and cheaply); survivors are promoted to the Old generation. Modern collectors (G1, the default; ZGC for low pause times) work concurrently to keep pauses short. Memory leaks in Java are references you forgot to drop: growing static collections, caches without eviction, listeners never removed.

9What is multithreading? How do you avoid race conditions and deadlocks?

Multithreading runs several tasks concurrently within one process, sharing memory. It improves responsiveness and uses multiple cores, but shared mutable state causes problems.

Race condition: the result depends on timing, e.g. two threads doing count++ (read, add, write) and losing an update. Fixes: synchronized methods or blocks, ReentrantLock, atomic classes (AtomicInteger), immutable objects, thread-safe collections (ConcurrentHashMap).

Deadlock: thread A holds lock 1 and waits for lock 2 while B holds lock 2 and waits for lock 1. Prevent it by acquiring locks in a consistent global order, using tryLock with a timeout, keeping critical sections small, and avoiding nested locks.

Also know: volatile ensures visibility but not atomicity; use ExecutorService thread pools instead of creating threads manually; CompletableFuture for async pipelines; virtual threads (Java 21) for massive numbers of blocking tasks.

10What are the SOLID principles?

  • S: Single responsibility: a class has one reason to change. Split InvoiceService (calculations) from InvoicePrinter (formatting).
  • O: Open/closed: open for extension, closed for modification. Add a new PaymentGateway implementation instead of adding another if in existing code.
  • L: Liskov substitution: subclasses must work wherever the parent is expected. A Square that breaks Rectangle's setters violates it.
  • I: Interface segregation: many small, focused interfaces beat one big one; clients shouldn't depend on methods they don't use.
  • D: Dependency inversion: depend on abstractions, not concrete classes; inject dependencies (this is what Spring's dependency injection does).

Follow-up questions often ask you to spot a violation in a code snippet and refactor it, so practise with small examples.

Keep going