Java Core
1. What is the SOLID principle?
Answer
The SOLID principles are a set of five design principles intended to make software designs more understandable, flexible, and maintainable.
1. Single Responsibility Principle (SRP)
What is it?
A class should have one, and only one, reason to change. It implies that a class should have only one job or responsibility.
Why we need it?
- Maintainability: Changes in one part of the system don't break unrelated parts.
- Readability: Smaller classes are easier to understand.
- Testability: Fewer dependencies make unit testing easier.
When/How to do it?
- When: You find a class doing multiple unrelated things (e.g.,
Userclass handling both authentication and email sending). - How: Split the class. Move email logic to an
EmailServiceand authentication to anAuthService.
2. Open/Closed Principle (OCP)
What is it?
Software entities (classes, modules, functions) should be open for extension but closed for modification.
Why we need it?
- Stability: You can add new features without risking bugs in existing, tested code.
- Scalability: Easier to add new behaviors as the system grows.
When/How to do it?
- When: You need to add a new type of behavior (e.g., a new payment method) and find yourself modifying a huge
if-elseblock. - How: Use Polymorphism (Interfaces/Abstract classes). Define a
Paymentinterface with apay()method. ImplementCreditCardPayment,PayPalPayment, etc. The main code just callspayment.pay()without knowing the specific implementation.
3. Liskov Substitution Principle (LSP)
What is it?
Subtypes must be substitutable for their base types without altering the correctness of the program. If Class B inherits from Class A, we should be able to pass B to any method expecting A without breaking anything.
Why we need it?
- Reliability: Ensures inheritance hierarchies make sense logically.
- Predictability: Prevents weird runtime errors when using polymorphism.
When/How to do it?
- When: A subclass throws a
NotSupportedExceptionfor a method defined in the parent class (e.g.,OstrichextendingBirdbut throwing exception onfly()). - How: Refactor the hierarchy. Maybe
Birdshouldn't havefly(). Create aFlyingBirdinterface or subclass. Ensure the subclass honors the "contract" of the parent class.
4. Interface Segregation Principle (ISP)
What is it?
Clients should not be forced to depend on interfaces they do not use. Prefer many specific interfaces over one general-purpose interface.
Why we need it?
- Decoupling: Classes only know about methods they actually need.
- Efficiency: Implementing a huge interface forces you to write empty methods for things you don't support.
When/How to do it?
- When: You have a "God Interface" (e.g.,
Workerhaswork(),eat(),sleep()). ARobotimplementsWorkerbut has to implementeat()(which it can't do). - How: Split the interface. Create
WorkableandFeedable.Humanimplements both,Robotonly implementsWorkable.
5. Dependency Inversion Principle (DIP)
What is it?
High-level modules should not depend on low-level modules. Both should depend on abstractions (interfaces). Abstractions should not depend on details. Details should depend on abstractions.
Why we need it?
- Flexibility: You can easily swap out low-level implementations (e.g., switch from MySQL to MongoDB) without changing high-level business logic.
- Testability: Allows mocking of dependencies during testing.
When/How to do it?
- When: Your
UserServiceinstantiates aMySQLDatabasedirectly (new MySQLDatabase()). Tightly coupled. - How: Use Dependency Injection.
UserServiceshould depend on aDatabaseinterface. Inject the specific implementation (MySQLDatabaseorMockDatabase) via the constructor.
2. What is OOP? Explain Inheritance, Encapsulation, Polymorphism, Abstraction
Answer
OOP (Object-Oriented Programming) is a programming paradigm based on the concept of "objects", which can contain data (fields) and code (methods). It aims to structure software by grouping related data and behaviors into reusable blueprints called Classes.
1. Encapsulation (封装)
What is it?
Bundling data (variables) and methods that operate on that data into a single unit (Class), and restricting direct access to some of an object's components.
Why we need it?
- Security: Prevents external code from modifying internal state directly and invalidly.
- Control: You can validate data in setters (e.g., age cannot be negative).
- Flexibility: You can change the internal implementation without affecting external code that uses the class.
When/How to do it?
- How: Declare class variables as
privateand provide publicgettersandsetters. - Example:
2. Abstraction (抽象)
What is it?
Hiding complex implementation details and showing only the essential features of the object. It focuses on what an object does instead of how it does it.
Why we need it?
- Simplicity: Reduces complexity by hiding unnecessary details.
- Focus: Helps developers focus on high-level logic.
When/How to do it?
- How: Use Abstract Classes or Interfaces.
- Example: You drive a car by using the steering wheel and pedals (Interface). You don't need to know how the engine combustion works (Implementation).
3. Inheritance (继承)
What is it?
A mechanism where one class (Child/Subclass) acquires the properties and behaviors (methods) of another class (Parent/Superclass).
Why we need it?
- Reusability: Avoid duplicating code. Common logic goes in the parent class.
- Extensibility: You can extend existing classes with new functionality.
When/How to do it?
- How: Use the
extendskeyword. - Example:
Dog extends Animal.Dogautomatically getseat()fromAnimalbut can addbark().
4. Polymorphism (多态)
What is it?
The ability of an object to take on many forms. It allows a method to do different things based on the object it is acting upon.
Why we need it?
- Flexibility: You can write code that works on the superclass type, but executes the specific subclass behavior at runtime.
- Scalability: Adding new subclasses doesn't require changing existing code that uses the superclass.
When/How to do it?
- Types:
- Compile-time (Overloading): Same method name, different parameters.
- Runtime (Overriding): Subclass provides specific implementation of a parent method.
- Example:
3. What is the Is-a and Has-a relationship in Java?
Answer
What is it?
- Is-a relationship (Inheritance): Occurs when a class inherits from another class.
- Has-a relationship (Composition/Aggregation): Occurs when a class contains an instance of another class.
Why we need it?
- Is-a: To establish a hierarchy and reuse code from a parent class.
- Has-a: To build complex objects from simpler ones (e.g., a Car has an Engine) and to favor composition over inheritance for flexibility.
When/How to do it?
- Is-a: Use
extendskeyword. Example:Dog extends Animal. - Has-a: Use a class field. Example:
class Car { Engine engine; }.
4. What is method overriding and method overloading?
Answer
What is it?
- Overloading: Defining multiple methods with the same name but different signatures (parameters) in the same class.
- Overriding: Providing a specific implementation in a subclass for a method already defined in its parent class.
Why we need it?
- Overloading: Increases readability and allows methods to handle different types/numbers of inputs.
- Overriding: Enables runtime polymorphism, allowing a subclass to define its specific behavior.
5. Difference between interface and abstract class
Answer
What is it?
| Feature | Interface | Abstract Class |
|---|---|---|
| Definition | A contract containing only abstract methods (pre-Java 8) and constants. | A class that cannot be instantiated and can contain both abstract and concrete methods. |
| Inheritance | Supports multiple inheritance (implements). | Supports single inheritance (extends). |
| Variables | public static final only. |
Can have instance variables. |
Why we need it?
- Interface: To define a capability or contract (e.g.,
Runnable,Serializable) that unrelated classes can implement. Enables multiple inheritance of type. - Abstract Class: To provide a common base with shared state and default behavior for closely related classes.
When/How to do it?
- Interface: Use
interfacekeyword. When you want to define "what it can do". - Abstract Class: Use
abstract classkeyword. When you want to define "what it is" and share code.
6. What is the diamond problem? How can we solve it?
Answer
What is it?
An ambiguity in multiple inheritance where a class inherits from two classes that define the same method. The compiler doesn't know which method to use.
Why we need it?
We "need" to solve it because Java interfaces support default methods, which can introduce this ambiguity if a class implements two interfaces with the same default method.
When/How to do it?
- Solution: Java forces the implementing class to override the conflicting method.
- How: Explicitly call the specific interface's method using
InterfaceName.super.method().
7. Is Java passing by value or passing by reference?
Answer
What is it?
Java is strictly pass-by-value.
Why we need it?
To ensure data integrity and avoid side effects where a method could unexpectedly replace the original object reference.
When/How to do it?
- Primitives: The actual value is passed. Changes inside the method don't affect the original variable.
- Objects: The copy of the reference (address) is passed. You can modify the object's fields via the reference, but you cannot reassign the original reference to a new object.
8. Difference between Array and ArrayList
Answer
What is it?
- Array: A fixed-size data structure that holds elements of the same type.
- ArrayList: A part of the Collection framework; a dynamic array that resizes itself.
Why we need it?
- Array: For performance-critical code where size is known and fixed. Efficient memory usage.
- ArrayList: For flexibility when the number of elements is unknown or changes.
When/How to do it?
- Array:
int[] arr = new int[5];. Use when size is static. - ArrayList:
List<Integer> list = new ArrayList<>();. Use when you needadd(),remove()operations.
9. Difference between ArrayList and LinkedList
Answer
What is it?
- ArrayList: Backed by a dynamic array.
- LinkedList: Backed by a doubly linked list (nodes with pointers).
Why we need it?
- ArrayList: Fast random access (\(O(1)\)
get) but slow insertion/deletion in the middle (\(O(N)\) shift). - LinkedList: Fast insertion/deletion (\(O(1)\)) if node is known, but slow random access (\(O(N)\) traversal).
When/How to do it?
- Use ArrayList for read-heavy applications (most common).
- Use LinkedList for write-heavy applications where you frequently add/remove from the beginning or middle.
10. What is an immutable class? How to create one?
Answer
What is it?
A class whose instances cannot be modified after they are created. Examples: String, Integer.
Why we need it?
- Thread-Safety: inherently thread-safe without synchronization.
- Security: Safe to use as Map keys or in sensitive contexts.
- Simplicity: Easier to reason about since state never changes.
When/How to do it?
- Declare the class as
final(prevent subclassing). - Make all fields
privateandfinal. - Provide no setters.
- Initialize all fields via constructor.
- Return deep copies of mutable fields in getters.
11. Why is String immutable?
Answer
What is it?
String objects in Java cannot be changed once created.
Why we need it?
- String Pool: Optimization to share identical string literals. Mutability would break this.
- Security: Strings are used for DB connections, file paths, etc.
- Thread Safety: Can be shared across threads safely.
- Caching HashCode: String's hash code is calculated once and cached, making it efficient for Map keys.
When/How to do it?
This is a design decision in Java. We just use String knowing it's immutable.
12. Difference between == and equals()
Answer
What is it?
==: Operator that compares object references (memory addresses) or primitive values.equals(): Method defined inObjectclass (default is==) but overridden by classes likeStringto compare content.
Why we need it?
To distinguish between "pointing to the same object" (==) and "having the same value" (equals).
When/How to do it?
- Use
==for primitives or checking if two variables refer to the exact same instance. - Use
.equals()for comparing logical equality of objects (e.g.,str1.equals(str2)).
13. Difference between String, StringBuilder, and StringBuffer
Answer
What is it?
- String: Immutable sequence of characters.
- StringBuilder: Mutable, non-thread-safe sequence.
- StringBuffer: Mutable, thread-safe sequence (synchronized).
Why we need it?
- String: General purpose, safety.
- StringBuilder: Efficient string manipulation (loops/concatenation) in single-threaded env.
- StringBuffer: Efficient manipulation in multi-threaded env (legacy).
When/How to do it?
- Use
Stringfor constants or literals. - Use
StringBuilderwhen building strings in a loop to avoid creating excessive temporary objects.
14. Difference between default and protected access modifier
Answer
What is it?
- default (package-private): No keyword. Access limited to the same package.
- protected: Access limited to the same package AND subclasses in other packages.
Why we need it?
To control visibility and encapsulation. protected is specifically for inheritance.
When/How to do it?
- Use default for internal helper classes within a package.
- Use protected for methods meant to be overridden or accessed by subclasses (e.g., template method pattern).
15. How does HashMap work internally?
Answer
What is it?
A map implementation based on a hash table. It uses an array of Node<K,V> (buckets).
Why we need it?
To retrieve values based on keys with average time complexity \(O(1)\).
When/How to do it?
Put Operation:
1. Calculate Hash: hashCode() of Key is called, then processed (hashing function) to reduce collisions.
2. Index Calculation: index = hash & (n - 1) (where n is array size).
3. Collision Handling: If the bucket is empty, add the Node. If not (collision), iterate the Linked List (or Red-Black Tree) in that bucket.
* If key exists (via equals()), update value.
* If key doesn't exist, append new Node.
4. Treeify: If a bucket's list size > 8 (and total capacity > 64), convert list to Red-Black Tree for \(O(\log N)\) access.
5. Resize: If size > threshold (capacity * loadFactor, default 0.75), array size doubles, and elements are rehashed.
Get Operation:
1. Calculate hash and index.
2. Check the first node in the bucket.
3. If mismatch, traverse the list/tree using equals() to find the key.
16. How does HashSet work internally?
Answer
What is it?
A collection that contains no duplicate elements.
Why we need it?
To efficiently store unique items and check for existence.
When/How to do it?
- Internally uses a HashMap.
- The element you add is stored as the Key.
- A dummy object
PRESENTis stored as the Value.
17. Difference between HashMap, SynchronizedMap, and ConcurrentHashMap
Answer
What is it?
Three ways to handle maps, varying in thread safety.
Why we need it?
- HashMap: Fast, non-thread-safe.
- SynchronizedMap: Wrapper that makes HashMap thread-safe by locking the entire map. Slow contention.
- ConcurrentHashMap: Thread-safe, highly optimized for concurrency.
When/How to do it?
- HashMap: Single-threaded apps.
- ConcurrentHashMap: Multi-threaded apps (uses bucket-level locking/CAS, allowing concurrent reads/writes).
18. Difference between List, Set, Map, Queue
Answer
What is it?
Core interfaces of Java Collections Framework.
Why we need it?
- List: Ordered, allows duplicates (e.g., shopping list).
- Set: Unordered, unique elements (e.g., unique IDs).
- Map: Key-Value pairs (e.g., dictionary).
- Queue: FIFO ordering (e.g., task processing).
When/How to do it?
Choose based on data requirements: Order? Duplicates? Key lookup? FIFO?
19. What are types of Exception?
Answer
What is it?
- Checked: Compile-time (extends
Exception). Must handle. - Unchecked: Runtime (extends
RuntimeException). Programming errors. - Error: System errors (extends
Error). JVM issues.
Why we need it?
To categorize errors into recoverable (Checked) vs. logic errors (Unchecked) vs. fatal errors (Error).
When/How to do it?
- Checked:
IOException(recoverable). - Unchecked:
NullPointerException(fix code). - Error:
OutOfMemoryError(restart/fix config).
20. How do you handle exceptions in Java?
Answer
What is it?
Mechanisms to gracefully manage runtime errors.
Why we need it?
To prevent application crashes and provide meaningful feedback or recovery.
When/How to do it?
try-catch: Capture and handle.finally: Cleanup resources.throws: Propagate to caller.try-with-resources: Auto-closeAutoCloseableresources.
21. How do you handle exceptions in your web application?
Answer
What is it?
Centralized error handling strategy.
Why we need it?
To avoid code duplication and return consistent JSON error responses to API clients.
When/How to do it?
- Use Global Exception Handler (
@ControllerAdvicein Spring). - Define custom exceptions (
UserNotFoundException). - Map exceptions to HTTP Status codes (404, 500).
22. Explain about Exception Propagation
Answer
What is it?
The process where an exception drops down the call stack to the previous method if not caught.
Why we need it?
Allows a higher-level method (which has more context) to handle the error instead of the low-level method where it occurred.
When/How to do it?
Automatic. Use throws keyword for Checked exceptions to allow propagation.
23. How to create customized exceptions?
Answer
What is it?
User-defined exception classes specific to business logic.
Why we need it?
To represent specific domain errors (e.g., InsufficientFundsException) rather than generic ones.
24. Difference between final, finally, finalize
Answer
What is it?
- final: Keyword for immutability/restriction.
- finally: Block for code execution after try-catch.
- finalize: Method called before Garbage Collection.
Why we need it?
- final: Constants, prevent overriding/inheritance.
- finally: Resource cleanup (close streams).
- finalize: (Deprecated) Rare cleanup logic.
When/How to do it?
final int MAX = 10;try { ... } finally { is.close(); }
25. How to create a thread?
Answer
What is it?
Starting a new path of execution.
Why we need it?
To perform concurrent operations.
When/How to do it?
- Extend
Threadclass. - Implement
Runnableinterface (preferred). - Implement
Callableinterface (for results). - Use
ExecutorService.
26. Difference between Runnable and Callable
Answer
What is it?
Interfaces for defining tasks for threads.
Why we need it?
To define unit of works.
When/How to do it?
- Runnable:
void run(). No result, cannot throw checked exception. - Callable:
V call(). Returns result, can throw exception. Use withFutureandExecutorService.
27. Why wait() and notify() are in Object class but not in Thread Class
Answer
What is it?
Methods for inter-thread communication.
Why we need it?
Because threads communicate by locking on shared data objects (monitors), not on threads themselves.
When/How to do it?
Every object has a monitor. wait() releases the object's lock.
28. What is join()?
Answer
What is it?
A method that allows one thread to pause until another thread finishes.
Why we need it?
To coordinate execution order (e.g., Main thread waits for Worker thread to finish data processing).
When/How to do it?
Call t1.join() inside the current thread.
29. Explain thread life cycle
Answer
What is it?
The states a thread goes through.
Why we need it?
To understand thread behavior and debugging.
When/How to do it?
States: New -> Runnable (Ready) -> Running -> Blocked/Waiting -> Terminated.
30. Difference between sleep() and wait()
Answer
What is it?
Methods to pause execution.
Why we need it?
sleep(): Delay execution.wait(): Inter-thread synchronization.
When/How to do it?
Thread.sleep(1000): Keeps lock.obj.wait(): Releases lock (must be in synchronized block).
31. What is countDownLatch?
Answer
What is it?
A synchronizer that allows one or more threads to wait until a set of operations completes.
Why we need it?
To ensure a service starts only after N dependent services are up.
When/How to do it?
Initialize with count N. Threads call countDown(). Waiting thread calls await().
32. What is semaphore?
Answer
What is it?
A variable used to control access to a shared resource using permits.
Why we need it?
To limit the number of concurrent accesses (Rate Limiting).
When/How to do it?
acquire() to get permit, release() to return.
33. Difference between Future and CompletableFuture
Answer
What is it?
Representations of async computation results.
Why we need it?
- Future: Basic async result. Blocking
get(). - CompletableFuture: Functional, non-blocking, chainable actions (
thenApply), combinable.
When/How to do it?
Use CompletableFuture for modern async programming.
34. Advantage of executor service instead of just create a thread and run it
Answer
What is it?
A framework for managing a pool of threads.
Why we need it?
Creating threads is expensive (OS resource). Executors reuse threads (pooling) and control the maximum number of concurrent threads to prevent resource exhaustion.
When/How to do it?
Executors.newFixedThreadPool(10).
35. What is a deadlock? How to handle deadlock?
Answer
What is it?
Threads waiting indefinitely for each other to release resources.
Why we need it?
We don't need it! We need to avoid it.
When/How to do it?
- Avoid: Acquire locks in a fixed order.
- Avoid: Use
tryLock()with timeout. - Detect: Use thread dump analysis tools.
36. What is synchronization? How do you do synchronization?
Answer
What is it?
Controlling access of multiple threads to shared resources.
Why we need it?
To prevent Race Conditions and data inconsistency.
When/How to do it?
synchronizedkeyword (method or block).ReentrantLock.Atomicclasses.
37. What is readWriteLock?
Answer
What is it?
A lock that separates read access from write access.
Why we need it?
Performance optimization. Allows multiple concurrent readers (shared lock) but only one exclusive writer. Good when reads >> writes.
When/How to do it?
ReentrantReadWriteLock.
38. What is a marker interface? Provide an example
Answer
What is it?
An empty interface (no methods).
Why we need it?
To provide metadata to the JVM or compiler indicating that a class has a special property.
When/How to do it?
- Example:
Serializable,Cloneable. - Check using
if (obj instanceof Serializable).
39. What does Serialization mean?
Answer
What is it?
Converting an object into a byte stream.
Why we need it?
To persist the object to a file, database, or send it over a network.
When/How to do it?
Implement Serializable interface. Use ObjectOutputStream.
40. What's the purpose of transient variables?
Answer
What is it?
Modifier keyword used in serialization.
Why we need it?
To ignore specific fields during serialization (e.g., sensitive passwords, or derived fields).
When/How to do it?
private transient String password;
41. How do you do the serialization and deserialization?
Answer
What is it?
The actual code implementation.
Why we need it?
To perform the save/load operation.
When/How to do it?
- Serialize:
out.writeObject(obj). - Deserialize:
Object obj = in.readObject().
42. What is memory leak?
Answer
What is it?
Objects are no longer needed but are still referenced, preventing GC from removing them.
Why we need it?
We need to avoid it to prevent OutOfMemoryError.
When/How to do it?
Common causes: Static collections holding objects forever, unclosed connections, improper equals/hashCode.
43. What are Young Generation, Old Generation and PermGen/MetaSpace?
Answer
What is it?
Regions of Java Heap/Memory.
Why we need it?
To optimize Garbage Collection (Generational Hypothesis: most objects die young).
When/How to do it?
- Young: New objects. Minor GC.
- Old: Long-lived objects. Major GC.
- Metaspace: Class metadata (non-heap).
44. What are the components of JVM?
Answer
What is it?
The internal architecture of the Java Virtual Machine.
Why we need it?
To load code, verify it, execute it, and manage memory.
When/How to do it?
- Class Loader: Loads classes.
- Runtime Data Areas: Memory (Heap, Stack, Method Area).
- Execution Engine: Interpreter, JIT, GC.
- Native Interface: Connect to OS.