OOPs Interview Preparation
A. OOP Fundamentals Object-Oriented Programming (OOP) is a programming paradigm that organizes software around objects rather than functions or procedures. An object represents a real-world entity and contains…
A. OOP Fundamentals
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
Object-Oriented Programming (OOP) is a programming paradigm that organizes software around objects rather than functions or procedures. An object represents a real-world entity and contains both data (fields) and behavior (methods).
The main goal of OOP is to build software that is modular, reusable, maintainable, scalable, and secure by modeling real-world objects.
Java follows OOP principles to simplify application development, especially for large enterprise applications.
Example
- Car
- Data: color, model, speed
- Behavior: start(), stop(), accelerate()
Here, the car is an object containing both properties and actions.
Interview Points
- OOP organizes code around objects.
- Objects contain both data and behavior.
- Improves code reusability and maintainability.
- Makes large applications easier to manage.
- Java is primarily based on OOP concepts.
The four pillars of Object-Oriented Programming are:
1. Encapsulation
Encapsulation means wrapping data and methods together into a single unit (class) and restricting direct access to the data using access modifiers.
Example:
- Private variables
- Public getter/setter methods
Benefits
- Data hiding
- Better security
- Controlled access
2. Abstraction
Abstraction means hiding implementation details and exposing only essential functionality.
In Java, abstraction is achieved using:
- Abstract classes
- Interfaces
Example:
When driving a car, you press the accelerator without knowing how the engine works.
Benefits
- Reduces complexity
- Improves maintainability
- Easier API design
3. Inheritance
Inheritance allows one class to acquire the properties and methods of another class using the extends keyword.
Example:
- Animal
- Dog extends Animal
Benefits
- Code reusability
- Easy maintenance
- Supports hierarchical design
4. Polymorphism
Polymorphism means one interface, multiple implementations.
Types:
- Compile-time Polymorphism (Method Overloading)
- Runtime Polymorphism (Method Overriding)
Example:
Payment
- Credit Card Payment
- UPI Payment
- Net Banking Payment
Each implements payment differently.
Benefits
- Flexibility
- Loose coupling
- Extensible applications
Interview Points
- Encapsulation → Data hiding
- Abstraction → Hide implementation
- Inheritance → Code reuse
- Polymorphism → Multiple implementations
A Class is a blueprint or template that defines the properties and behaviors of an object.
An Object is the actual instance of a class that occupies memory and can perform operations.
Example
class Student {
String name;
}
Student s1 = new Student();
- Student → Class
- s1 → Object
| Class | Object |
|---|---|
| Blueprint | Real instance |
| Logical entity | Physical entity |
| No memory for instance variables until objects are created | Occupies memory |
| Defines attributes and methods | Uses those attributes and methods |
| Created once | Multiple objects can be created |
Interview Points
- Class is a template.
- Object is an instance of a class.
- Objects consume memory.
- One class can create many objects.
An instance is a specific object created from a class using the new keyword.
Each instance has its own copy of instance variables while sharing the class’s method definitions.
Example
Employee emp1 = new Employee();
Employee emp2 = new Employee();
Here:
- emp1 and emp2 are two separate instances.
- Each has its own data.
- Both use the same class definition.
Interview Points
- Instance means object created from a class.
- Created using the new keyword.
- Each instance has independent state.
- Multiple instances can exist simultaneously.
OOP helps developers build software that is modular, reusable, maintainable, secure, and scalable by organizing code into objects.
Instead of writing large procedural code, applications are divided into smaller classes where each class has a specific responsibility.
In enterprise applications like Spring Boot microservices, OOP improves code organization and enables easier testing and future enhancements.
Interview Points
- Promotes modular design.
- Encourages code reuse through inheritance and composition.
- Improves maintainability.
- Supports abstraction and encapsulation.
- Makes large enterprise applications easier to develop and scale.
Procedural programming focuses on functions, whereas OOP focuses on objects that combine data and behavior.
Advantages of OOP
- Better code reusability using inheritance and composition.
- Easier maintenance due to modular class design.
- Data security through encapsulation.
- Flexibility using polymorphism.
- Reduced complexity through abstraction.
- Easier unit testing and debugging.
- Better scalability for large enterprise applications.
- Supports real-world object modeling.
Comparison
| Procedural Programming | Object-Oriented Programming |
|---|---|
| Function-based | Object-based |
| Data and functions are separate | Data and methods are together |
| Less secure | More secure through encapsulation |
| Difficult to maintain large systems | Easier to maintain |
| Less reusable | Highly reusable |
| Limited scalability | Highly scalable |
Interview Points
- OOP is more suitable for enterprise applications.
- Better maintainability and scalability.
- Encourages reusable and modular code.
- Provides better security and flexibility.
No, Java is not 100% Object-Oriented.
Although Java is primarily based on Object-Oriented Programming principles, it includes several non-object-oriented features.
Reasons
1. Primitive Data Types
Java provides primitive types like:
- int
- char
- boolean
- double
- float
These are not objects.
2. Static Members
Static variables and methods belong to the class rather than an object.
Example:
Math.max();
No object creation is required.
3. Primitive Operations
Operations like:
int a = 10;
int b = 20;
int c = a + b;
are performed directly on primitive values instead of objects.
4. Performance Optimization
Primitive data types are provided to improve performance and reduce memory usage compared to wrapper objects like Integer or Double.
Interview Points
- Java is mostly object-oriented, but not purely object-oriented.
- Primitive data types are not objects.
- Static methods can be accessed without creating objects.
- Wrapper classes (Integer, Double, Character, etc.) provide object representations of primitive types when needed.
Expected Interview Conclusion:
“Java is considered a predominantly object-oriented language because most application development follows OOP principles. However, it is not 100% object-oriented due to the presence of primitive data types, static members, and certain language features introduced for performance and practicality.”
B. Class & Object
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
A Class is a blueprint or template used to create objects. It defines the state (instance variables/fields) and behavior (methods) that its objects will have.
A class itself does not occupy memory for instance variables until an object is created.
Example
class Employee {
String name;
int age;
void work() {
System.out.println("Employee is working");
}
}
Here:
- Employee → Class
- name, age → State
- work() → Behavior
Interview Points
- Class is a blueprint for objects.
- Defines fields and methods.
- Logical entity (not a physical object).
- Multiple objects can be created from one class.
An Object is a runtime instance of a class. It represents a real-world entity and contains its own copy of instance variables while sharing the class’s method definitions.
Objects occupy memory and interact with other objects through method calls.
Example
Employee emp = new Employee();
Here:
- Employee → Class
- emp → Object (Instance)
Interview Points
- Object is an instance of a class.
- Created during runtime.
- Stores its own state.
- Can invoke methods defined in the class.
Objects are commonly created using the new keyword.
Syntax
ClassName obj = new ClassName();
Example
Student student = new Student();
The above statement performs three operations:
- Declares a reference variable (student).
- Creates a new object using new.
- Assigns the object’s reference to the variable.
Objects can also be created using:
- Reflection (Class.forName(), Constructor.newInstance())
- Cloning (clone())
- Deserialization
- Factory methods (e.g., Calendar.getInstance())
Interview Points
- Most common way is using the new keyword.
- new allocates memory and calls the constructor.
- Reference variable stores the object’s memory address (reference), not the object itself.
When the new keyword is used, Java performs the following steps internally:
Internal Process
- JVM checks whether sufficient heap memory is available.
- Memory is allocated in the Heap.
- All instance variables are initialized with default values.
- int → 0
- boolean → false
- Object → null
- The constructor is invoked to initialize the object.
- A reference to the newly created object is returned.
- The reference is assigned to the reference variable.
Example
Employee emp = new Employee();
Interview Points
- Memory allocation happens in the Heap.
- Constructor is automatically called.
- Default values are assigned before constructor execution.
- new returns the object’s reference.
Objects are stored in the Heap Memory.
The reference variable that points to the object is stored:
- Inside the Stack (if it’s a local variable)
- Inside another object (if it’s an instance variable)
Memory Layout
Stack Memory Heap Memory
emp -------------> Employee Object
name = null
age = 0
Interview Points
- Objects are stored in Heap.
- Local references are stored in Stack.
- Heap is managed by the Garbage Collector.
Yes.
A class can exist without creating any objects because it is only a blueprint. It gets loaded into memory when required, but no memory for instance variables is allocated until an object is created.
Example
class Student {
}
This class is perfectly valid even if no object is created.
Interview Points
- Class can exist independently.
- Objects are optional.
- Instance memory is allocated only after object creation.
Yes.
A single class can create any number of objects. Each object has its own copy of instance variables but shares the same class definition and method implementations.
Example
Employee e1 = new Employee();
Employee e2 = new Employee();
Employee e3 = new Employee();
Here:
- Three different objects
- Same class
- Independent data
Interview Points
- One class can create multiple objects.
- Each object has its own state.
- Methods are shared logically through the class definition.
#
C. Constructors
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
A constructor is a special member of a class used to initialize objects. It is automatically invoked when an object is created using the new keyword.
A constructor has the same name as the class and does not have any return type, not even void.
Example
class Employee {
Employee() {
System.out.println("Object Created");
}
}
Interview Points
- Initializes objects.
- Automatically called during object creation.
- Same name as the class.
- No return type.
- Invoked only once per object.
Java mainly has two types of constructors.
1. Default (No-Argument) Constructor
A constructor without parameters.
class Student {
Student() {
System.out.println("Default Constructor");
}
}
Note: If you do not write any constructor, the compiler automatically provides a default constructor. Once you define any constructor explicitly, the compiler no longer generates one.
2. Parameterized Constructor
Used to initialize objects with specific values.
class Student {
Student(String name) {
this.name = name;
}
}
Interview Points
- Default/No-Argument Constructor
- Parameterized Constructor
- Compiler provides a default constructor only if none is written.
| Constructor | Method |
|---|---|
| Initializes an object | Performs operations |
| Same name as class | Any valid name |
| No return type | Must have a return type (or void) |
| Called automatically | Called explicitly |
| Executes once per object creation | Can be called multiple times |
| Cannot be inherited | Can be inherited (subject to access rules) |
Interview Points
- Constructor initializes; method performs actions.
- Constructor has no return type.
- Constructor is invoked automatically.
Yes.
Constructors can be overloaded by defining multiple constructors with different parameter lists.
Example
class Student {
Student() {}
Student(String name) {}
Student(String name, int age) {}
}
This allows objects to be initialized in different ways.
Interview Points
- Constructor overloading is supported.
- Different parameter lists are required.
- Supports flexible object initialization.
No.
Constructors cannot be overridden because they are not inherited by subclasses.
When a child object is created, the parent constructor is called using super(), but the child defines its own constructor.
Interview Points
- Constructors are not inherited.
- Overriding is only possible for inherited methods.
- Parent constructor is invoked using super().
Yes.
A private constructor prevents object creation from outside the class.
Example
class Singleton {
private Singleton() {
}
}
Private constructors are commonly used in:
- Singleton Design Pattern
- Utility classes
- Factory methods
Interview Points
- Restricts object creation.
- Used in Singleton and utility classes.
- Improves control over object instantiation.
A Singleton class is designed to ensure that only one instance of the class exists throughout the application’s lifecycle.
Making the constructor private prevents external code from creating additional objects using the new keyword.
The class exposes a static method (commonly getInstance()) that creates the object once and returns the same instance on every call.
Interview Points
- Prevents multiple object creation.
- Ensures only one instance exists.
- Commonly used for configuration managers, logging, caching, and shared resources.
Constructor chaining is the process of invoking one constructor from another constructor to avoid code duplication and centralize initialization logic.
It can happen:
- Within the same class using this().
- Between parent and child classes using super().
Example
class Student {
Student() {
this("Unknown");
}
Student(String name) {
System.out.println(name);
}
}
Interview Points
- Reuses initialization logic.
- Reduces duplicate code.
- Implemented using this() and super().
this() is used to invoke another constructor within the same class.
Rules:
- Must be the first statement in the constructor.
- Only one constructor call (this() or super()) can be the first statement.
Example
class Student {
Student() {
this("John");
}
Student(String name) {
System.out.println(name);
}
}
Interview Points
- Calls another constructor in the same class.
- Used for constructor chaining.
- Must be the first statement.
super() is used to invoke the constructor of the immediate parent class.
If it is not written explicitly, the compiler automatically inserts super() as the first statement, provided the parent has a no-argument constructor.
Example
class Animal {
Animal() {
System.out.println("Animal Constructor");
}
}
class Dog extends Animal {
Dog() {
super();
System.out.println("Dog Constructor");
}
}
Interview Points
- Invokes the parent class constructor.
- Supports constructor chaining across inheritance.
- Must be the first statement in the constructor.
- Compiler inserts it automatically if omitted and a no-argument parent constructor exists.
D. Encapsulation
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
Encapsulation is one of the four pillars of OOP. It is the process of wrapping data (fields) and methods (behavior) together into a single unit (class) while restricting direct access to the data.
In Java, encapsulation is achieved by:
- Declaring fields as private
- Providing controlled access through public getter and setter methods
Encapsulation protects an object’s internal state and ensures that data is modified only in a controlled manner.
Example
class Employee {
private double salary;
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
if (salary > 0) {
this.salary = salary;
}
}
}
Interview Points
- Combines data and methods into a single class.
- Restricts direct access to data.
- Achieved using private fields and public methods.
- Provides controlled access and data protection.
Encapsulation helps build secure, maintainable, and robust applications by protecting the internal state of an object.
Benefits
- Prevents unauthorized access to data.
- Allows validation before updating data.
- Reduces coupling between classes.
- Improves maintainability.
- Allows implementation changes without affecting client code.
- Helps enforce business rules.
Real-world Example
In a banking application, an account balance should not be modified directly:
❌ Incorrect
account.balance = -5000;
✔ Correct
account.withdraw(5000);
The withdraw() method validates the transaction before updating the balance.
Interview Points
- Improves security.
- Enables validation.
- Reduces coupling.
- Improves maintainability.
- Hides implementation details.
Encapsulation is achieved by:
- Declaring instance variables as private.
- Providing public getters to read data.
- Providing public setters (or other methods) to modify data after validation.
- Exposing only the required operations while hiding internal implementation.
Example
class Student {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
if (name != null) {
this.name = name;
}
}
}
Interview Points
- Private fields.
- Public getter/setter methods.
- Validation before modification.
- Controlled access to object state.
Fields are declared private to protect an object’s internal state from direct modification.
If fields are public, any class can modify them, which may lead to invalid or inconsistent data.
Private fields ensure that all updates go through methods where validation, logging, or business rules can be applied.
Example
private int age;
public void setAge(int age) {
if (age >= 0) {
this.age = age;
}
}
Interview Points
- Prevents unauthorized access.
- Protects data integrity.
- Enables validation.
- Supports encapsulation.
Getter and Setter methods are public methods used to access and modify private fields.
- Getter → Returns the value of a field.
- Setter → Updates the value of a field, usually after validation.
Example
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
Interview Points
- Getter reads data.
- Setter updates data.
- Used with private fields.
- Setter can include validation and business logic.
Yes.
Immutable classes are a strong example of encapsulation because their internal state is protected and cannot be modified after object creation.
Characteristics of an immutable class:
- Class is often final.
- Fields are private and final.
- No setter methods.
- State is initialized through the constructor.
- Mutable fields are returned as defensive copies.
Example
final class Employee {
private final String name;
Employee(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Interview Points
- Immutable classes are encapsulated.
- No setters.
- State cannot change after creation.
- Thread-safe by design.
#
E. Inheritance
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
Inheritance is an OOP concept that allows one class (child/subclass) to acquire the properties and methods of another class (parent/superclass).
It promotes code reuse, enables hierarchical relationships, and supports runtime polymorphism.
Java uses the extends keyword to implement inheritance.
Example
class Animal {
void eat() {
System.out.println("Eating");
}
}
class Dog extends Animal {
void bark() {
System.out.println("Barking");
}
}
Here, Dog inherits the eat() method from Animal.
Interview Points
- Enables code reuse.
- Represents an “is-a” relationship.
- Supports polymorphism.
- Implemented using extends.
Inheritance helps avoid duplicate code by allowing common functionality to be defined in a parent class and reused by child classes.
Benefits
- Code reusability.
- Easier maintenance.
- Reduced code duplication.
- Supports method overriding.
- Enables runtime polymorphism.
- Represents real-world hierarchical relationships.
Example
Instead of implementing login() in every employee type, define it once in the Employee class and let Manager, Developer, and Tester inherit it.
Interview Points
- Promotes code reuse.
- Simplifies maintenance.
- Supports polymorphism.
- Models “is-a” relationships.
Java supports the following inheritance types through classes:
1. Single Inheritance
One child inherits from one parent.
A
|
B
2. Multilevel Inheritance
A child becomes the parent of another class.
A
|
B
|
C
3. Hierarchical Inheritance
Multiple child classes inherit from the same parent.
A
/ | \\
B C D
Multiple Inheritance (Classes)
❌ Not supported.
Hybrid Inheritance
❌ Not supported directly through classes, but it can be achieved using interfaces.
Interview Points
- Supported: Single, Multilevel, Hierarchical.
- Not supported with classes: Multiple and Hybrid.
- Multiple inheritance is possible through interfaces.
Java does not support multiple inheritance with classes to avoid ambiguity, commonly known as the Diamond Problem.
Example
A
/ \\
B C
\\ /
D
If both B and C override the same method from A, the compiler cannot determine which implementation D should inherit.
To eliminate this ambiguity and simplify the language, Java allows a class to extend only one class.
Interview Points
- Prevents the Diamond Problem.
- Eliminates ambiguity.
- Simplifies method resolution.
- Improves maintainability.
Java allows a class to implement multiple interfaces because interfaces define contracts rather than maintaining object state.
If two interfaces provide the same default method, the implementing class must explicitly override it to resolve the conflict.
Example
interface Camera {}
interface MusicPlayer {}
class Smartphone implements Camera, MusicPlayer {
}
Interview Points
- A class can implement multiple interfaces.
- Supports multiple inheritance of type.
- Conflicting default methods must be overridden explicitly.
The extends keyword is used to create an inheritance relationship between two classes.
The child class automatically inherits accessible fields and methods from the parent class.
Example
class Vehicle {
}
class Car extends Vehicle {
}
Interview Points
- Establishes inheritance.
- Child inherits accessible members.
- Supports code reuse and polymorphism.
The super keyword refers to the immediate parent class.
It is used to:
- Invoke the parent constructor (super()).
- Access parent methods (super.method()).
- Access parent fields (super.variable).
Example
class Animal {
void sound() {
System.out.println("Animal Sound");
}
}
class Dog extends Animal {
void sound() {
super.sound();
System.out.println("Dog Bark");
}
}
Interview Points
- Refers to the immediate parent class.
- Calls parent constructor.
- Accesses parent methods and variables.
- Useful when child overrides parent methods.
When an object of a child class is created, constructors execute from parent to child.
The parent constructor always executes first because the child object depends on the parent portion being initialized before its own initialization.
Example
class Parent {
Parent() {
System.out.println("Parent");
}
}
class Child extends Parent {
Child() {
System.out.println("Child");
}
}
Output:
Parent
Child
Execution Order
- Parent constructor.
- Child constructor.
Interview Points
- Parent constructor executes first.
- super() is invoked implicitly if not written.
- Object initialization proceeds from top to bottom in the inheritance hierarchy.
When a child class inherits from a parent class, not all methods behave the same way.
Rules
- Public methods → Inherited and accessible everywhere.
- Protected methods → Inherited and accessible in subclasses.
- Package-private (default) methods → Inherited only if the child is in the same package.
- Private methods → Not inherited because they are accessible only within the parent class.
- Final methods → Inherited but cannot be overridden.
- Static methods → Inherited, but they are hidden, not overridden.
- Abstract methods → Must be implemented by the first concrete subclass unless it is also abstract.
Interview Points
- Private methods are not inherited.
- Final methods cannot be overridden.
- Static methods are hidden, not overridden.
- Access modifiers determine method visibility.
- Abstract methods require implementation by concrete subclasses.
F. Polymorphism
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
Polymorphism is one of the four pillars of OOP. The word Polymorphism means “many forms.” It allows the same method or interface to behave differently depending on the object or parameters.
In Java, polymorphism enables one reference to represent different object types, making applications more flexible and extensible.
Example
Payment payment = new CreditCardPayment();
payment.pay();
payment = new UPIPayment();
payment.pay();
Here, the same pay() method behaves differently based on the actual object.
Interview Points
- Means “one interface, many implementations.”
- Improves flexibility and extensibility.
- Supports loose coupling.
- Achieved through method overloading and method overriding.
Java supports two types of polymorphism.
1. Compile-time Polymorphism (Static Polymorphism)
Achieved through Method Overloading.
The compiler determines which method to call based on the method signature.
Example:
add(int a, int b)
add(double a, double b)
2. Runtime Polymorphism (Dynamic Polymorphism)
Achieved through Method Overriding.
The JVM determines which method to execute based on the actual object created.
Example:
Animal animal = new Dog();
animal.sound();
The Dog implementation is executed.
Interview Points
- Compile-time → Method Overloading.
- Runtime → Method Overriding.
- Runtime polymorphism is based on dynamic method dispatch.
| Method Overloading | Method Overriding |
|---|---|
| Same method name with different parameters | Same method signature in parent and child |
| Occurs within the same class (or inherited class) | Requires inheritance |
| Compile-time polymorphism | Runtime polymorphism |
| Return type alone cannot differentiate methods | Return type can be covariant |
| Improves readability | Enables dynamic behavior |
| Resolved by compiler | Resolved by JVM at runtime |
Interview Points
- Overloading → Different parameters.
- Overriding → Same signature.
- Overloading is compile-time.
- Overriding is runtime.
Compile-time polymorphism is achieved through method overloading, where multiple methods have the same name but different parameter lists.
The compiler determines which method to invoke during compilation based on the method signature.
Example
class Calculator {
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
}
Interview Points
- Achieved using method overloading.
- Method selection happens during compilation.
- Faster than runtime polymorphism because no dynamic dispatch is required.
Runtime polymorphism is achieved through method overriding, where a child class provides its own implementation of a parent class method.
The JVM decides which method to execute at runtime based on the actual object.
Example
Animal animal = new Dog();
animal.sound();
Although the reference type is Animal, the Dog implementation executes.
Interview Points
- Achieved using method overriding.
- Requires inheritance.
- Method selection happens at runtime.
- Implemented using dynamic method dispatch.
No.
Static methods belong to the class, not to objects. Therefore, they are hidden, not overridden.
Example
class Parent {
static void show() {}
}
class Child extends Parent {
static void show() {}
}
Calling the method depends on the reference type, not the object.
Interview Points
- Static methods are class-level methods.
- They participate in method hiding, not overriding.
- Runtime polymorphism does not apply to static methods.
No.
Private methods are not inherited by child classes, so they cannot be overridden.
If a child class defines a method with the same name, it is a completely new method.
Interview Points
- Private methods are not inherited.
- Overriding requires inheritance.
- Same method name in child does not override the parent’s private method.
No.
A method declared with the final keyword cannot be overridden because the parent class intends its implementation to remain unchanged.
Example
class Parent {
final void display() {
}
}
Any attempt to override display() in a subclass results in a compilation error.
Interview Points
- Final methods are inherited.
- They cannot be overridden.
- Used when behavior should remain fixed.
Runtime polymorphism enables applications to be flexible, loosely coupled, and easily extensible.
Instead of coding against concrete implementations, we code against abstractions (interfaces or parent classes). The actual implementation can change without affecting the client code.
Real-world Example
Payment payment = paymentFactory.getPaymentMethod();
payment.pay();
Whether the implementation is CreditCardPayment, UPIPayment, or NetBankingPayment, the calling code remains unchanged.
This principle is heavily used in:
- Spring Framework (Dependency Injection)
- Spring Boot
- Hibernate
- Strategy Design Pattern
- Factory Design Pattern
Interview Points
- Promotes loose coupling.
- Improves maintainability.
- Makes applications extensible.
- Widely used in Spring through dependency injection.
#
G. Abstraction
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
Abstraction is one of the four pillars of OOP. It means hiding implementation details and exposing only the essential functionality to the user.
The user interacts with what an object does, not how it does it.
In Java, abstraction is achieved using:
- Abstract classes
- Interfaces
Real-world Example
When driving a car, you press the accelerator and brake without knowing the internal workings of the engine.
Interview Points
- Hides implementation details.
- Exposes only essential functionality.
- Reduces complexity.
- Achieved using abstract classes and interfaces.
Abstraction simplifies application development by hiding unnecessary implementation details and exposing only the required operations.
Benefits
- Reduces complexity.
- Improves maintainability.
- Enables loose coupling.
- Improves security by hiding implementation.
- Makes APIs easier to use.
- Allows implementation changes without affecting client code.
Example
The List interface allows developers to use ArrayList or LinkedList interchangeably without changing business logic.
Interview Points
- Simplifies complex systems.
- Hides implementation details.
- Promotes loose coupling.
- Makes code easier to maintain and extend.
| Abstract Class | Interface |
|---|---|
| Declared using abstract keyword | Declared using interface keyword |
| Can have abstract and concrete methods | Can have abstract, default, static, and private methods (Java 8/9+) |
| Can have constructors | Cannot have constructors |
| Can have instance variables | Can have constants (public static final) |
| Supports single inheritance | Multiple interfaces can be implemented |
| Uses extends | Uses implements |
| Best for shared state and common implementation | Best for defining a contract or capability |
Interview Points
- Abstract class → Common functionality + shared state.
- Interface → Contract and multiple inheritance.
- Prefer interfaces for loose coupling.
Yes.
Although an abstract class cannot be instantiated directly, it can have constructors.
The constructor is executed when a subclass object is created, helping initialize common fields.
Example
abstract class Animal {
Animal() {
System.out.println("Animal Constructor");
}
}
class Dog extends Animal {
}
Creating a Dog object invokes the Animal constructor first.
Interview Points
- Abstract classes can have constructors.
- Constructors initialize common data.
- Executed during child object creation.
Yes.
An abstract class can contain both:
- Abstract methods (without implementation).
- Concrete methods (with implementation).
Example
abstract class Animal {
abstract void sound();
void sleep() {
System.out.println("Sleeping");
}
}
Here:
- sound() must be implemented by subclasses.
- sleep() is inherited as it is.
Interview Points
- Can contain both abstract and concrete methods.
- Useful for sharing common functionality.
- Subclasses implement only the abstract methods.
Yes.
Since Java 8 and Java 9, interfaces can contain methods with implementations.
Types of methods in an interface
- Default methods (Java 8)
- Static methods (Java 8)
- Private methods (Java 9, used internally within the interface)
Example
interface Vehicle {
default void start() {
System.out.println("Starting");
}
static void stop() {
System.out.println("Stopping");
}
}
Interview Points
- Java 8 introduced default and static methods.
- Java 9 introduced private interface methods.
- Helps extend interfaces without breaking existing implementations.
Use an abstract class when related classes share common state or implementation, and you want to provide default behavior while forcing subclasses to implement specific methods.
Use an interface when you want to define a capability or contract that can be implemented by unrelated classes.
Prefer an Abstract Class when
- Classes have a common parent.
- You need instance variables (shared state).
- You want constructors.
- You want to provide partial implementation.
- You expect subclasses to reuse common code.
Prefer an Interface when
- You need multiple inheritance of type.
- You want to define a contract.
- Unrelated classes should implement the same behavior.
- You want loose coupling and flexibility.
Real-world Example
- Abstract Class: Vehicle → shared fields like speed, engineNumber, common methods like start().
- Interface: Drivable → implemented by Car, Bike, or even a Robot, regardless of their inheritance hierarchy.
Interview Points
- Abstract class for shared state and common implementation.
- Interface for contracts, capabilities, and multiple inheritance.
- In modern Java, prefer interfaces for extensibility and abstract classes when shared implementation or state is required.
H. Interface
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
An Interface is a blueprint that defines a contract which implementing classes must follow. It specifies what a class should do, but not necessarily how it should do it.
A class implements an interface using the implements keyword.
Interfaces are primarily used to achieve abstraction, loose coupling, and multiple inheritance of type.
Example
interface Payment {
void pay();
}
class CreditCardPayment implements Payment {
@Override
public void pay() {
System.out.println("Payment by Credit Card");
}
}
Interview Points
- Defines a contract.
- Achieves abstraction.
- Implemented using implements.
- Supports loose coupling and polymorphism.
- A class can implement multiple interfaces.
Interfaces are used to define a common contract that multiple classes can implement independently. This allows applications to depend on abstractions instead of concrete implementations.
Benefits
- Promotes loose coupling.
- Supports runtime polymorphism.
- Enables multiple inheritance.
- Improves flexibility and maintainability.
- Makes applications easier to test and extend.
- Widely used in frameworks like Spring for Dependency Injection.
Real-world Example
Payment payment = new UPIPayment();
payment.pay();
Later, UPIPayment can be replaced with CreditCardPayment without changing the client code.
Interview Points
- Defines contracts.
- Supports Dependency Injection.
- Promotes loose coupling.
- Enables multiple implementations.
- Makes applications easier to extend and test.
| Interface | Abstract Class |
|---|---|
| Defines a contract | Provides partial implementation |
| Uses implements | Uses extends |
| Supports multiple inheritance | Supports single inheritance |
| No constructors | Can have constructors |
| Variables are public static final | Can have instance variables |
| Best for unrelated classes sharing a capability | Best for related classes sharing common state and behavior |
| Achieves abstraction | Achieves abstraction with code reuse |
Interview Points
- Interface → Contract.
- Abstract Class → Shared implementation.
- Interface supports multiple inheritance.
- Abstract class supports shared state.
A Marker Interface is an interface that contains no methods or fields. Its purpose is to provide metadata to the JVM or frameworks indicating that a class has a special capability.
Examples
- Serializable
- Cloneable
- Remote
Example:
class Employee implements Serializable {
}
Here, Serializable tells the JVM that the object can be serialized.
Note: Modern Java also uses annotations (e.g., @FunctionalInterface) for metadata, but marker interfaces are still used in certain APIs.
Interview Points
- No methods or constants.
- Used to mark special behavior.
- Examples: Serializable, Cloneable, Remote.
A Functional Interface is an interface that contains exactly one abstract method.
It is the foundation of Lambda Expressions and the Stream API introduced in Java 8.
It can also have:
- Default methods
- Static methods
- Private methods (Java 9+)
Example
@FunctionalInterface
interface Calculator {
int add(int a, int b);
}
Common functional interfaces provided by Java include:
- Runnable
- Callable
- Predicate
- Function
- Consumer
- Supplier
Interview Points
- Exactly one abstract method.
- Supports Lambda Expressions.
- Annotated with @FunctionalInterface.
- May contain default and static methods.
Default methods were introduced in Java 8 to allow interfaces to provide method implementations.
They are declared using the default keyword.
This feature was introduced mainly to extend existing interfaces without breaking existing implementations.
Example
interface Vehicle {
default void start() {
System.out.println("Vehicle Started");
}
}
Interview Points
- Introduced in Java 8.
- Declared using default.
- Helps maintain backward compatibility.
- Can be overridden by implementing classes.
Java 8 introduced static methods inside interfaces.
These methods belong to the interface itself and are called using the interface name.
They are not inherited by implementing classes.
Example
interface MathUtil {
static int square(int n) {
return n * n;
}
}
Usage:
MathUtil.square(5);
Interview Points
- Introduced in Java 8.
- Belong to the interface.
- Invoked using the interface name.
- Cannot be overridden.
Private methods were introduced in Java 9.
They are used to avoid code duplication among default and static methods inside the same interface.
They are not accessible outside the interface.
Example
interface Vehicle {
default void start() {
log();
}
private void log() {
System.out.println("Logging...");
}
}
Interview Points
- Introduced in Java 9.
- Used internally by the interface.
- Reduce duplicate code.
- Cannot be accessed by implementing classes.
A Java class can implement multiple interfaces, allowing it to inherit multiple contracts.
Example
interface Camera {}
interface MusicPlayer {}
class Smartphone implements Camera, MusicPlayer {
}
If two interfaces contain the same default method, the implementing class must override it to resolve the conflict.
Interview Points
- Java supports multiple interface inheritance.
- Achieves multiple inheritance of type.
- Conflicting default methods must be overridden explicitly.
Yes.
All variables declared inside an interface are implicitly:
- public
- static
- final
This means they are constants and cannot be modified.
Example
interface AppConfig {
int MAX_USERS = 100;
}
The compiler automatically treats it as:
public static final int MAX_USERS = 100;
Interview Points
- Interface variables are constants.
- Implicitly public static final.
- Cannot have instance variables.
- Must be initialized at declaration.
#
I. Method Overloading
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
Method Overloading is a feature where multiple methods in the same class have the same name but different parameter lists.
It is an example of Compile-time Polymorphism, as the compiler determines which method to invoke based on the method signature.
Example
class Calculator {
int add(int a, int b) {
return a + b;
}
int add(int a, int b, int c) {
return a + b + c;
}
double add(double a, double b) {
return a + b;
}
}
Interview Points
- Same method name.
- Different parameter list.
- Compile-time polymorphism.
- Improves code readability.
For methods to be overloaded, the method signature must be different.
A different signature can be achieved by:
- Changing the number of parameters.
- Changing the data types of parameters.
- Changing the order of parameters (when parameter types differ).
Valid Examples
display(int a)
display(int a, int b)
display(double a)
display(String s, int a)
Invalid Example
display(int a)
display(int b)
Only parameter names are different, so this is not overloading.
Interview Points
- Method name must remain the same.
- Parameter list must differ.
- Parameter names do not matter.
- Return type alone does not create overloading.
No.
Changing only the return type does not create a new method signature.
The compiler cannot distinguish which method to call because method selection is based on the method name and parameter list, not the return type.
Invalid Example
int add(int a, int b)
double add(int a, int b)
This results in a compilation error.
Interview Points
- Return type is not part of the method signature.
- Compiler resolves overloaded methods using parameters only.
- Changing only the return type causes a compile-time error.
Yes.
Constructors can be overloaded by defining multiple constructors with different parameter lists.
This allows objects to be initialized in different ways.
Example
class Student {
Student() {}
Student(String name) {}
Student(String name, int age) {}
}
Interview Points
- Constructor overloading is supported.
- Different parameter lists are required.
- Provides flexible object initialization.
Method overloading improves the usability and readability of code by allowing related operations to share the same method name.
Advantages
- Improves code readability.
- Reduces the need for multiple method names.
- Supports compile-time polymorphism.
- Makes APIs easier to use.
- Provides flexibility for different input types.
Real-world Example
The System.out.println() method is overloaded to accept different data types such as int, double, char, String, and boolean.
Interview Points
- Improves readability.
- Reduces code duplication.
- Provides a cleaner API.
- Enables compile-time polymorphism.
- Widely used in Java libraries and frameworks.
J. Method Overriding
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
Method Overriding is a feature where a child class provides its own implementation of a method that is already defined in its parent class using the same method signature.
It is the basis of Runtime Polymorphism because the JVM decides which method to execute based on the actual object at runtime.
Example
class Animal {
void sound() {
System.out.println("Animal Sound");
}
}
class Dog extends Animal {
@Override
void sound() {
System.out.println("Dog Barks");
}
}
Interview Points
- Child class provides its own implementation.
- Same method signature as the parent.
- Requires inheritance.
- Achieves runtime polymorphism.
- Method resolution happens at runtime.
A method can be overridden only if the following rules are satisfied:
Rules
- Parent and child methods must have the same method name.
- Parameter list must be identical.
- Return type must be the same or covariant.
- Child method cannot reduce the visibility of the parent method.
- Child method cannot throw broader checked exceptions.
- Static methods cannot be overridden.
- Final methods cannot be overridden.
- Private methods cannot be overridden because they are not inherited.
Interview Points
- Same signature is mandatory.
- Requires inheritance.
- Visibility cannot be reduced.
- Return type can be covariant.
- Static, final, and private methods cannot be overridden.
While overriding, the child class cannot reduce the accessibility of the parent method.
Examples
| Parent Method | Child Method | Valid? |
|---|---|---|
| public | public | ✔ Yes |
| protected | public | ✔ Yes |
| protected | protected | ✔ Yes |
| public | protected | ❌ No |
| protected | private | ❌ No |
A child class may increase visibility but cannot decrease it.
Interview Points
- Visibility can be increased.
- Visibility cannot be reduced.
- Ensures overridden methods remain accessible.
Exception handling follows these rules:
Checked Exceptions
- Child method can throw the same checked exception.
- Child method can throw a subclass of the parent’s checked exception.
- Child method cannot throw a broader checked exception.
Unchecked Exceptions
- Runtime exceptions can be thrown freely because the compiler does not enforce them.
Example
class Parent {
void read() throws IOException {}
}
class Child extends Parent {
@Override
void read() throws FileNotFoundException {}
}
FileNotFoundException is valid because it is a subclass of IOException.
Interview Points
- Checked exceptions cannot be broadened.
- Narrower checked exceptions are allowed.
- Runtime exceptions have no such restriction.
A Covariant Return Type allows an overriding method to return a subclass of the parent’s return type.
Introduced in Java 5.
Example
class Animal {}
class Dog extends Animal {}
class Parent {
Animal getAnimal() {
return new Animal();
}
}
class Child extends Parent {
@Override
Dog getAnimal() {
return new Dog();
}
}
Interview Points
- Introduced in Java 5.
- Child can return a subclass type.
- Improves flexibility without breaking polymorphism.
@Override tells the compiler that a method is intended to override a parent method.
If the method does not actually override any inherited method, the compiler generates an error.
Example
class Parent {
void display() {}
}
class Child extends Parent {
@Override
void display() {}
}
Advantages
- Detects spelling mistakes.
- Prevents accidental overloading.
- Improves code readability.
- Provides compile-time validation.
Interview Points
- Optional but highly recommended.
- Provides compile-time checking.
- Improves readability and maintainability.
Static methods belong to the class, not to individual objects.
Overriding works through dynamic method dispatch, which depends on objects. Since static methods are resolved at compile time, they participate in method hiding, not overriding.
Example
class Parent {
static void show() {
System.out.println("Parent");
}
}
class Child extends Parent {
static void show() {
System.out.println("Child");
}
}
Parent p = new Child();
p.show();
Output:
Parent
The method is selected based on the reference type, not the actual object.
Interview Points
- Static methods belong to the class.
- Resolved at compile time.
- Method hiding occurs instead of overriding.
- Runtime polymorphism does not apply.
#
K. this & super Keywords
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
this is a reference variable that refers to the current object of the class.
It is commonly used to access the current object’s fields and methods, especially when parameter names and instance variable names are the same.
Example
class Employee {
private String name;
Employee(String name) {
this.name = name;
}
}
Interview Points
- Refers to the current object.
- Eliminates naming conflicts.
- Used within instance methods and constructors.
this has several important uses in Java.
Uses
1. Refer to the current object’s instance variables
this.name = name;
2. Invoke another constructor in the same class
this();
3. Invoke the current object’s methods
this.display();
4. Pass the current object as an argument
process(this);
5. Return the current object
Commonly used in the Builder Pattern and method chaining.
return this;
Interview Points
- Refers to the current object.
- Calls another constructor.
- Invokes current methods.
- Passes or returns the current object.
super is a reference to the immediate parent class.
It is used to access parent constructors, methods, and variables.
Uses
- Call parent constructor.
- Access parent methods.
- Access parent variables hidden by child variables.
Example
class Parent {
void display() {
System.out.println("Parent");
}
}
class Child extends Parent {
void display() {
super.display();
}
}
Interview Points
- Refers to the immediate parent.
- Invokes parent constructor.
- Accesses overridden methods and hidden fields.
| this() | super() |
|---|---|
| Calls another constructor in the same class | Calls the immediate parent constructor |
| Used for constructor chaining within the class | Used for constructor chaining across inheritance |
| Refers to the current class | Refers to the parent class |
| Must be the first statement | Must also be the first statement |
Interview Points
- this() → Same class constructor.
- super() → Parent constructor.
- Only one can appear as the first statement in a constructor.
Object construction in Java follows a strict initialization order.
Before a constructor executes its own initialization logic, Java must first determine which constructor should execute first—either another constructor in the same class (this()) or the parent constructor (super()).
Allowing other statements before these calls could lead to partially initialized objects or inconsistent state.
Interview Points
- Ensures proper object initialization.
- Parent object must be initialized before the child.
- Constructor chaining must happen first.
- Only one of this() or super() can be the first statement.
#
L. Access Modifiers
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
Access modifiers control the visibility of classes, methods, variables, and constructors.
| Modifier | Same Class | Same Package | Subclass (Different Package) | Other Packages |
|---|---|---|---|---|
| public | ✔ | ✔ | ✔ | ✔ |
| protected | ✔ | ✔ | ✔ | ✖ |
| default (package-private) | ✔ | ✔ | ✖ | ✖ |
| private | ✔ | ✖ | ✖ | ✖ |
Interview Points
- public → Accessible everywhere.
- protected → Same package + subclasses.
- default → Same package only.
- private → Same class only.
public provides the highest visibility.
A public member can be accessed from:
- The same class.
- Any class in the same package.
- Subclasses.
- Any package.
Interview Points
- public has the widest accessibility.
- Used for APIs and methods intended for external use.
| Protected | Default (Package-private) |
|---|---|
| Accessible within the same package | Accessible within the same package |
| Accessible by subclasses in different packages | Not accessible by subclasses outside the package |
| Declared using the protected keyword | No keyword is specified |
Example
protected void display() {}
void display() {}
Interview Points
- Both work within the same package.
- Only protected allows access to subclasses in other packages.
- Default has package-level visibility only.
No.
A top-level class can only be declared as:
- public
- default (package-private)
A top-level class cannot be private or protected because it must be accessible for the JVM and other classes to use it.
However, nested (inner) classes can be declared as private, protected, public, or default.
Example
public class Employee {
}
class Student {
}
Interview Points
- Top-level classes cannot be private or protected.
- Inner classes can use all access modifiers.
When overriding a method, the child class cannot reduce the visibility of the parent method.
Examples
| Parent | Child | Valid |
|---|---|---|
| public | public | ✔ |
| protected | public | ✔ |
| protected | protected | ✔ |
| public | protected | ✖ |
| protected | private | ✖ |
The child class may keep the same visibility or make it more accessible, but it cannot make it more restrictive.
Interview Points
- Visibility can stay the same or increase.
- Visibility cannot decrease.
- Ensures polymorphism works correctly and inherited methods remain accessible.
M. Object Class
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
The Object class is the root (superclass) of the Java class hierarchy. It is present in the java.lang package, and every class in Java directly or indirectly inherits from it.
Because every class extends Object, all Java objects automatically inherit common methods such as equals(), hashCode(), toString(), clone(), and getClass().
Example
class Employee {
}
Internally, the compiler treats it as:
class Employee extends Object {
}
Interview Points
- Root class of Java.
- Located in java.lang package.
- Every class inherits from it directly or indirectly.
- Provides common methods for all Java objects.
Every class extends Object so that all objects share a common set of fundamental behaviors.
This enables Java to treat every object uniformly and allows methods like equals(), toString(), and hashCode() to be available for every object.
It also supports features like:
- Runtime polymorphism
- Reflection
- Collections Framework
- Generic programming
Interview Points
- Provides common behavior to all objects.
- Enables polymorphism.
- Simplifies the Collections Framework.
- Supports reflection and runtime type information.
Some of the most commonly used methods are:
| Method | Purpose |
|---|---|
| equals() | Compares object equality |
| hashCode() | Returns hash value of the object |
| toString() | Returns string representation |
| clone() | Creates a copy of the object |
| getClass() | Returns runtime class information |
| wait() | Makes the current thread wait |
| notify() | Wakes one waiting thread |
| notifyAll() | Wakes all waiting threads |
| finalize() *(Deprecated)* | Cleanup before GC (deprecated since Java 9) |
Interview Points
- equals() → Equality
- hashCode() → Hash-based collections
- toString() → Object representation
- clone() → Object copying
- getClass() → Reflection
- wait()/notify() → Thread communication
The equals() method is used to compare the logical equality (content) of two objects.
The default implementation in the Object class compares memory references, meaning it returns true only if both references point to the same object.
Most business classes override equals() to compare object data instead of memory addresses.
Example
class Employee {
int id;
@Override
public boolean equals(Object obj) {
Employee e = (Employee) obj;
return this.id == e.id;
}
}
Interview Points
- Used for logical equality.
- Default implementation compares references.
- Frequently overridden in business/domain classes.
The hashCode() method returns an integer value that represents the object’s hash code.
Hash-based collections such as HashMap, HashSet, and Hashtable use this value to determine where an object should be stored.
If two objects are equal according to equals(), they must produce the same hash code.
Example
@Override
public int hashCode() {
return Objects.hash(id);
}
Interview Points
- Returns an integer hash value.
- Used by hash-based collections.
- Equal objects must have equal hash codes.
The toString() method returns the string representation of an object.
By default, it returns:
ClassName@HexadecimalHashCode
Most classes override it to provide meaningful information for logging and debugging.
Example
@Override
public String toString() {
return "Employee{id=1, name='John'}";
}
Interview Points
- Converts an object to a readable string.
- Commonly overridden for debugging and logging.
- Automatically called by System.out.println(object).
The clone() method creates a copy of an existing object.
To use cloning:
- The class must implement the Cloneable marker interface.
- Override the clone() method.
- Call super.clone().
By default, clone() performs a shallow copy.
Example
class Employee implements Cloneable {
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
Interview Points
- Creates a copy of an object.
- Default implementation performs a shallow copy.
- Requires the Cloneable interface.
- Deep copy must be implemented manually when needed.
The getClass() method returns the runtime class information of an object.
It is commonly used in reflection and debugging.
Example
Employee emp = new Employee();
System.out.println(emp.getClass().getName());
Output:
Employee
Interview Points
- Returns runtime class information.
- Used in reflection.
- Helpful for debugging and frameworks like Spring and Hibernate.
finalize() was a method called by the Garbage Collector before reclaiming an object’s memory.
It was intended for resource cleanup, but its execution was unpredictable and could lead to performance and reliability issues.
Therefore, it was deprecated in Java 9 and should no longer be used.
Instead, Java recommends:
- Try-with-resources
- AutoCloseable
- Explicit resource cleanup using close()
Interview Points
- Invoked by the Garbage Collector before object destruction.
- Deprecated since Java 9.
- Execution timing is not guaranteed.
- Prefer try-with-resources and AutoCloseable.
#
N. equals() & hashCode()
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
By default, equals() compares object references, not object content.
In real-world applications, we usually need to compare business data rather than memory addresses.
Therefore, we override equals() to define logical equality.
Example
Employee e1 = new Employee(101);
Employee e2 = new Employee(101);
Without overriding:
e1.equals(e2); // false
After overriding:
e1.equals(e2); // true
Interview Points
- Default compares references.
- Override for logical/content equality.
- Common in domain objects and entities.
hashCode() is used by hash-based collections to determine where an object should be stored.
If equals() is overridden but hashCode() is not, logically equal objects may end up in different buckets, causing incorrect behavior.
Therefore, whenever equals() is overridden, hashCode() should also be overridden.
Interview Points
- Used by HashMap and HashSet.
- Ensures equal objects have the same hash code.
- Improves lookup performance.
Java defines the following contract:
Rules
- If two objects are equal according to equals(), they must have the same hash code.
- If two objects have the same hash code, they may or may not be equal.
- Unequal objects can have different or even the same hash codes (hash collisions are possible).
Example
Employee e1 = new Employee(101);
Employee e2 = new Employee(101);
If:
e1.equals(e2) == true
Then:
e1.hashCode() == e2.hashCode()
must also be true.
Interview Points
- Equal objects ⇒ Same hash code.
- Same hash code ≠ Equal objects necessarily.
- Hash collisions are allowed.
Case 1: Override equals() but not hashCode()
Objects may be logically equal but produce different hash codes.
Result:
- HashMap cannot locate the object correctly.
- HashSet may store duplicate logical objects.
Case 2: Override hashCode() but not equals()
Objects may have the same hash code, but equality still depends on reference comparison.
Result:
- Collections behave incorrectly because logically equal objects are not recognized as equal.
Interview Points
- Always override both together.
- Overriding only one breaks the Java contract.
- Leads to unexpected behavior in hash-based collections.
HashMap uses both methods during insertion and retrieval.
During put(key, value)
- hashCode() determines the bucket where the key should be stored.
- If multiple keys map to the same bucket (collision), equals() checks whether the key already exists.
- If equal, the value is updated; otherwise, a new entry is added.
During get(key)
- hashCode() identifies the correct bucket.
- equals() compares keys within that bucket to find the exact entry.
Interview Flow (Very Important)
“HashMap first calls hashCode() to locate the bucket. If multiple keys exist in that bucket due to hash collisions, it then calls equals() to identify the correct key. That’s why both methods must be overridden together. If only equals() is overridden, logically equal objects may be placed in different buckets and retrieval can fail.”
Interview Points
- hashCode() finds the bucket.
- equals() finds the exact key within the bucket.
- Both methods work together.
- Essential for the correct behavior and performance of HashMap, HashSet, and other hash-based collections.
O. Immutable Class
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
An Immutable Class is a class whose objects cannot be modified after they are created. Once an object’s state is initialized through the constructor, it remains unchanged throughout its lifetime.
If any modification is required, a new object is created instead of modifying the existing one.
The most common example in Java is the String class.
Example
JavaString s1 = “Java”;
String s2 = s1.concat(” Programming”);
Here:
–
s1 remains “Java”.
–
s2 refers to a new object “Java Programming”.
Interview Points
–
Object state cannot change after creation.
–
No setter methods.
–
Thread-safe by design.
–
Example: String, wrapper classes (Integer, Long, etc.), LocalDate.
To create an immutable class, follow these rules:
Rules
–
Declare the class as final so it cannot be subclassed.
–
Make all fields private and final.
–
Initialize fields only through the constructor.
–
Do not provide setter methods.
–
Provide only getter methods.
–
If the class contains mutable objects (e.g., Date, List), return defensive copies instead of the original objects.
Example
Javapublic final class Employee {
private final int id;
private final String name;
public Employee(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
}
Interview Points
–
Class should be final.
–
Fields should be private final.
–
No setters.
–
Constructor initializes all fields.
–
Return defensive copies for mutable fields.
String is immutable to provide security, performance, thread safety, and efficient memory management.
Reasons
1. String Pool
Multiple variables can safely share the same string object because its value cannot change.
JavaString s1 = “Java”;
String s2 = “Java”;
Both references point to the same object.
2. Security
Strings are widely used for:
–
Database URLs
–
File paths
–
Network connections
–
Class loading
Immutability prevents accidental or malicious modification.
3. Thread Safety
Multiple threads can safely share the same String object without synchronization.
4. HashMap Performance
Since a string never changes, its hash code can be cached, making lookups in HashMap much faster.
Interview Points
–
Supports String Pool.
–
Improves security.
–
Thread-safe.
–
Cached hash code improves HashMap performance.
Immutable objects provide several advantages in enterprise applications.
Benefits
–
Thread-safe without synchronization.
–
Easier to understand and debug.
–
Safe to share across multiple threads.
–
Prevents accidental modification.
–
Improves security.
–
Enables object caching.
–
Ideal for use as keys in HashMap.
–
Simplifies concurrent programming.
Interview Points
–
Thread safety.
–
Better security.
–
Predictable behavior.
–
Safe for caching and collections.
Immutable ObjectMutable ObjectState cannot change after creationState can be modifiedNo settersSetters are usually presentThread-safe by designSynchronization may be requiredSafe to share across threadsCareful synchronization requiredExample: String, Integer, LocalDateExample: StringBuilder, ArrayList, HashMap
Interview Points
–
Immutable → Safer and thread-safe.
–
Mutable → Flexible but requires careful synchronization.
–
Prefer immutable objects wherever possible for shared data.
##
P. Association, Aggregation & Composition
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
Association is a relationship where two independent objects interact with each other, but both can exist independently.
There is no ownership between the objects.
Example
–
Teacher teaches Student.
–
Customer places Order.
–
Doctor treats Patient.
Even if one object is removed, the other still exists.
Interview Points
–
General relationship between objects.
–
No ownership.
–
Both objects have independent lifecycles.
–
Weakest relationship among the three.
Aggregation is a special type of association representing a “has-a” relationship where one object contains another object, but the contained object can exist independently.
The parent object does not own the lifecycle of the child object.
Example
Department —-> Employee
If the Department is deleted, Employees still exist and can be assigned to another department.
Real-world Examples
–
Department → Employees
–
Library → Books
–
Team → Players
–
School → Teachers
Interview Points
–
“Has-a” relationship.
–
Weak ownership.
–
Child object can exist independently.
–
Represents shared ownership.
Composition is a stronger form of aggregation where one object completely owns another object.
The child object’s lifecycle depends on the parent. If the parent object is destroyed, the child object is also destroyed.
Example
House —-> Room
If the House is demolished, its Rooms no longer exist independently.
Real-world Examples
–
House → Room
–
Car → Engine
–
Human → Heart
–
Order → OrderItem
Interview Points
–
Strong “has-a” relationship.
–
Parent owns the child.
–
Child cannot exist independently.
–
Strongest relationship among the three.
AggregationCompositionWeak “has-a” relationshipStrong “has-a” relationshipChild can exist independentlyChild depends on parentWeak ownershipStrong ownershipParent and child have separate lifecyclesParent and child share the same lifecycleExample: Department → EmployeeExample: House → Room
Interview Points
–
Aggregation → Independent lifecycle.
–
Composition → Dependent lifecycle.
–
Composition represents stronger ownership.
RelationshipReal-world ExampleExplanationAssociationDoctor ↔ PatientBoth exist independently.AssociationTeacher ↔ StudentBoth have separate lifecycles.AggregationDepartment → EmployeeEmployees can move to another department.AggregationTeam → PlayerPlayers can join another team.CompositionHouse → RoomRooms cannot exist without the house.CompositionCar → EngineEngine is an integral part of the car.CompositionOrder → OrderItemOrder items belong to a specific order.
Interview Points
–
Association → Interaction only.
–
Aggregation → Weak ownership.
–
Composition → Strong ownership and lifecycle dependency.
The strength of relationships is:
Association
↓
Aggregation
↓
Composition
–
Association → Simple interaction, no ownership.
–
Aggregation → Weak ownership, independent lifecycle.
–
Composition → Strong ownership, dependent lifecycle.
Expected Interview Conclusion
“Composition is the strongest relationship because the child object’s lifecycle depends entirely on the parent. Aggregation is weaker since the child can exist independently, while Association is simply a relationship between independent objects without ownership.”
Interview Points
–
Composition is the strongest relationship.
–
Aggregation has weak ownership.
–
Association represents only interaction.
–
Remember the hierarchy: Association → Aggregation → Composition.
<button type=”button” class=”text-token-text-secondary hover:bg-token-surface-hover rounded-lg” aria-label=”Copy response”
Q. Object Cloning
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
Cloning is the process of creating a copy of an existing object. Instead of creating a new object and manually copying all field values, Java provides the clone() method to duplicate an object.
The clone() method is defined in the Object class.
To support cloning:
–
The class must implement the Cloneable marker interface.
–
Override the clone() method.
–
Call super.clone().
By default, Java performs a shallow copy.
Example
Javaclass Employee implements Cloneable {
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
Interview Points
–
Creates a copy of an existing object.
–
Uses clone() method.
–
Requires the Cloneable interface.
–
Default cloning performs a shallow copy.
Shallow Copy
A shallow copy duplicates the object, but references to nested objects are shared between the original and the cloned object.
If a referenced object is modified, both objects see the change.
Example
Employee
|
Address <—– Shared
Deep Copy
A deep copy duplicates the object along with all referenced objects.
Each object has its own independent copy.
Example
Employee ——> Address
Employee Clone -> Address Clone
Comparison
Shallow CopyDeep CopyCopies object onlyCopies object and referenced objectsReferences are sharedReferences are duplicatedFasterSlightly slowerLess memoryMore memoryMay cause side effectsCompletely independent objects
Interview Points
–
Shallow copy shares referenced objects.
–
Deep copy creates independent copies.
–
clone() performs a shallow copy by default.
–
Deep copy must be implemented manually.
Cloneable is a marker interface in Java.
It does not contain any methods. It simply indicates that the class allows object cloning.
If a class does not implement Cloneable and clone() is called, the JVM throws a CloneNotSupportedException.
Example
Javaclass Employee implements Cloneable {
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
Interview Points
–
Marker interface.
–
No methods.
–
Enables object cloning.
–
Without it, CloneNotSupportedException is thrown.
Although Java provides cloning, it is generally discouraged because it has several design and maintenance issues.
Reasons
–
clone() performs only a shallow copy by default.
–
Deep copying complex object graphs is difficult.
–
Uses the protected clone() method from Object.
–
Requires implementing the Cloneable marker interface.
–
Does not invoke constructors, which may bypass initialization logic.
–
Makes immutable and final fields harder to handle correctly.
Because of these limitations, modern Java applications rarely rely on cloning.
Interview Points
–
Default cloning is shallow.
–
Complex to implement correctly.
–
Constructors are not called.
–
Generally avoided in modern Java.
Modern Java applications usually prefer safer alternatives to cloning.
Alternatives
1. Copy Constructor
JavaEmployee copy = new Employee(original);
2. Factory Method
JavaEmployee copy = Employee.copyOf(original);
3. Builder Pattern
Useful when objects have many fields.
4. Serialization/Deserialization
Can create a deep copy for serializable object graphs, though it is generally slower.
Interview Points
–
Copy constructor is the most common approach.
–
Builder pattern is useful for complex objects.
–
Factory methods improve readability.
–
These approaches are preferred over clone().
##
R. Inner Classes
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
Java supports four types of inner classes.
–
Member Inner Class
–
Static Nested Class
–
Local Inner Class
–
Anonymous Inner Class
Interview Points
–
Four types of inner classes.
–
Used to logically group related classes.
–
Improve encapsulation and code organization.
A Static Nested Class is declared with the static keyword inside another class.
Since it belongs to the outer class rather than its instances, it cannot directly access non-static members of the outer class.
Example
Javaclass Outer {
static class Inner {
void display() {
System.out.println(“Static Nested Class”);
}
}
}
Interview Points
–
Declared using static.
–
Does not require an outer class object.
–
Can access only static members directly.
–
Used when the nested class is independent of outer object state.
A Member Inner Class is a non-static class defined inside another class.
It has access to all members of the outer class, including private members.
Example
Javaclass Outer {
private int value = 10;
class Inner {
void show() {
System.out.println(value);
}
}
}
Interview Points
–
Non-static inner class.
–
Requires an outer class object.
–
Can access all members of the outer class.
–
Useful when tightly coupled with the outer class.
A Local Inner Class is declared inside a method, constructor, or block.
Its scope is limited to that block and it cannot be accessed from outside.
Example
Javaclass Outer {
void display() {
class Local {
void show() {
System.out.println(“Local Inner Class”);
}
}
new Local().show();
}
}
Interview Points
–
Declared inside a method.
–
Accessible only within that method.
–
Used for method-specific logic.
An Anonymous Inner Class is an inner class without a name.
It is declared and instantiated in a single expression.
It is commonly used to provide a one-time implementation of an interface or abstract class.
Example
JavaRunnable task = new Runnable() {
@Override
public void run() {
System.out.println(“Running”);
}
};
Note: In modern Java, Lambda Expressions are often preferred over anonymous classes for functional interfaces.
Interview Points
–
No class name.
–
One-time implementation.
–
Commonly replaced by lambdas for functional interfaces.
–
Reduces boilerplate code.
Inner classes are used when a class is closely related to another class and does not need to exist independently.
Common Use Cases
–
Encapsulating helper classes.
–
Event handling (especially in Swing/JavaFX).
–
Callback implementations.
–
One-time implementations using anonymous classes.
–
Builder Pattern.
–
Grouping related functionality.
Interview Points
–
Improves encapsulation.
–
Groups related classes.
–
Reduces namespace pollution.
–
Frequently used in Builder Pattern and callback implementations.
##
S. Object Life Cycle
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
An object’s lifecycle describes the stages it goes through from creation until it becomes eligible for Garbage Collection.
Stages
–
Class Loading
–
Memory Allocation
–
Object Creation
–
Object Initialization
–
Object Usage
–
Eligible for Garbage Collection
–
Memory Reclaimed by Garbage Collector
Life Cycle
Class Loaded
↓
Memory Allocated
↓
Constructor Executed
↓
Object Initialized
↓
Object Used
↓
Reference Removed
↓
Eligible for Garbage Collection
↓
Memory Reclaimed
Interview Points
–
Object lives from creation until garbage collection.
–
Garbage Collector automatically reclaims unused objects.
–
Destruction timing is not deterministic.
When the new keyword is used:
–
JVM checks whether sufficient heap memory is available.
–
Memory is allocated in the Heap.
–
Instance variables receive default values.
–
A reference to the object is returned.
Example
JavaEmployee emp = new Employee();
Interview Points
–
Objects are stored in Heap memory.
–
Reference variables are typically stored in Stack (for local variables).
–
Memory allocation occurs before constructor execution.
Object creation begins when the new keyword is executed.
The JVM allocates memory, creates the object, and returns a reference to it.
Example
JavaEmployee emp = new Employee();
Interview Points
–
Triggered by the new keyword.
–
Heap memory is allocated.
–
Returns an object reference.
After memory allocation, Java initializes the object.
Initialization Order
–
Default values are assigned to instance variables.
–
Instance variable initializers execute.
–
Instance initialization blocks execute (if present).
–
Parent constructor executes.
–
Child constructor executes.
The object is then ready for use.
Interview Points
–
Default values assigned first.
–
Parent constructor executes before child constructor.
–
Constructor initializes the object’s state.
An object becomes eligible for Garbage Collection when it is no longer reachable by any live reference.
Common scenarios include:
–
Reference set to null.
–
Reference variable goes out of scope.
–
Reference is reassigned to another object.
–
Objects involved in isolated reference cycles with no live references.
Example
JavaEmployee emp = new Employee();
emp = null;
Now the object is eligible for Garbage Collection.
Interview Points
–
Eligibility does not mean immediate collection.
–
Garbage Collector decides when to reclaim memory.
–
Reachability determines eligibility.
Java does not provide explicit object destruction.
When an object becomes unreachable, the Garbage Collector (GC) automatically reclaims its heap memory at an appropriate time.
The exact time of reclamation is not guaranteed and should never be relied upon in application logic.
Interview Points
–
Managed automatically by the Garbage Collector.
–
Developers cannot explicitly destroy objects.
–
GC timing is non-deterministic.
finalize() was a method that the Garbage Collector could invoke before reclaiming an object’s memory.
It was intended for resource cleanup, but its execution was unpredictable, could delay garbage collection, and often caused performance and reliability issues.
Because of these drawbacks, finalize() was deprecated in Java 9.
Today, Java recommends:
–
Try-with-resources
–
AutoCloseable
–
Explicit cleanup using close()
Interview Points
–
finalize() was called before garbage collection.
–
Deprecated since Java 9.
–
Execution is not guaranteed.
–
Prefer try-with-resources and AutoCloseable for resource management.
<button type=”button” class=”text-token-text-secondary hover:bg-token-surface-hover rounded-lg” aria-label=”Copy response”
T. Interview Scenario Questions
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
A Banking Application is one of the best examples to explain all four OOP pillars.
1. Encapsulation
The customer’s account details such as balance, account number, and PIN are declared as private.
The balance cannot be modified directly.
Javaaccount.deposit(5000);
account.withdraw(2000);
Only controlled methods can modify the balance after validation.
2. Abstraction
The customer only sees operations like:
–
Deposit
–
Withdraw
–
Check Balance
The internal implementation (database update, transaction logging, fraud detection) remains hidden.
3. Inheritance
Account
|
————————-
Savings Current Salary
All account types share common behavior like:
–
deposit()
–
withdraw()
–
getBalance()
while implementing their own business rules.
4. Polymorphism
JavaAccount account = new SavingsAccount();
account.calculateInterest();
account = new CurrentAccount();
account.calculateInterest();
The same method executes different implementations depending on the actual object.
Interview Conclusion
“In a banking application, encapsulation protects customer data, abstraction hides complex banking operations, inheritance promotes code reuse among account types, and polymorphism allows different account types to provide their own business behavior while exposing a common interface.”
Interview Points
–
Encapsulation → Protect account data.
–
Abstraction → Hide banking implementation.
–
Inheritance → Reuse common account logic.
–
Polymorphism → Different account behavior.
A simple and scalable design:
Employee (Abstract)
————————-
id
name
salary
department
calculateSalary()
|
—————————————
Developer Manager Tester
calculateSalary() calculateSalary() calculateSalary()
Why this design?
–
Common properties remain in Employee.
–
Role-specific logic is implemented in subclasses.
–
Runtime polymorphism allows common processing.
Example:
JavaEmployee employee = new Developer();
employee.calculateSalary();
Interview Points
–
Common fields in parent class.
–
Role-specific behavior in child classes.
–
Abstract class + runtime polymorphism.
–
Easily extensible for future employee types.
Choose Composition when objects have a “has-a” relationship and behavior should be reusable without creating a tight parent-child dependency.
Examples:
–
Car has an Engine.
–
Order has OrderItems.
–
Computer has Keyboard.
Choose Inheritance only when there is a genuine “is-a” relationship.
Examples:
–
Dog is an Animal.
–
Manager is an Employee.
Interview Conclusion
“If the relationship is ‘has-a’, I prefer composition. If it’s truly ‘is-a’, inheritance is appropriate.”
Interview Points
–
Composition → Has-a relationship.
–
Inheritance → Is-a relationship.
–
Prefer composition for flexibility.
Composition is preferred because it creates looser coupling.
Inheritance tightly couples child classes to parent implementations.
Composition allows behavior to be changed simply by replacing one object with another.
Example:
Instead of
Car extends DieselEngine
Use
Car
|
Engine
Now the engine can easily become:
–
PetrolEngine
–
ElectricEngine
–
HybridEngine
without changing the Car class.
This follows the design principle:
“Favor Composition over Inheritance.”
Interview Points
–
Loose coupling.
–
Better flexibility.
–
Easier maintenance.
–
Easier testing.
–
Preferred in modern frameworks like Spring.
Important Rules
–
final class
–
private final fields
–
constructor initialization
–
no setters
–
defensive copies for mutable fields
Example:
Javapublic final class Employee {
private final int id;
private final String name;
public Employee(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
}
Interview Points
–
final class.
–
private final fields.
–
Constructor initialization.
–
No setters.
–
Thread-safe.
The recommended implementation is the Bill Pugh Singleton, which is thread-safe and uses lazy initialization without synchronization overhead.
Javapublic class Singleton {
private Singleton() {}
private static class Holder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
}
Why?
–
Lazy initialization.
–
Thread-safe.
–
No synchronization overhead.
–
JVM guarantees safe class loading.
Interview Points
–
Private constructor.
–
Static instance.
–
Global access point.
–
Prefer Bill Pugh or Enum Singleton in modern Java.
Consider a Payment System.
Payment
|
———————–
UPI Card NetBanking
Each payment type overrides:
Javapay()
Example:
JavaPayment payment = new UPIPayment();
payment.pay();
The JVM executes the UPIPayment implementation at runtime.
Interview Points
–
Same method.
–
Different implementations.
–
Runtime polymorphism.
–
Real-world example: payment processing.
Runtime polymorphism works using Dynamic Method Dispatch.
Example:
JavaAnimal animal = new Dog();
animal.sound();
Internal flow:
–
Compiler checks that Animal has a sound() method.
–
JVM looks at the actual object (Dog) during runtime.
–
JVM uses the object’s method table (vtable) to invoke Dog.sound().
Interview Conclusion
“The compiler verifies the method based on the reference type, but the JVM selects the actual implementation at runtime based on the object’s type.”
Interview Points
–
Dynamic Method Dispatch.
–
JVM decides at runtime.
–
Based on object type, not reference type.
HashMap uses both methods together.
put()
–
hashCode() finds the bucket.
–
equals() checks whether the key already exists.
get()
–
hashCode() locates the bucket.
–
equals() identifies the exact key.
If equals() is overridden without hashCode(), logically equal keys may end up in different buckets, leading to failed lookups or duplicate keys.
“HashMap first uses hashCode() to locate the bucket and then uses equals() to find the exact key inside that bucket. Therefore, whenever we override equals(), we must also override hashCode().”
Interview Points
–
hashCode → Bucket.
–
equals → Exact key.
–
Always override both together.
Payment (Interface)
pay()
—————————-
UPIPayment CardPayment WalletPayment
Client code:
JavaPayment payment = new CardPayment();
payment.pay();
Advantages:
–
Loose coupling.
–
Easy to add new payment methods.
–
Runtime polymorphism.
–
Open for extension, closed for modification (Open/Closed Principle).
Interview Points
–
Interface-based design.
–
Runtime polymorphism.
–
Easy to extend.
–
Supports Dependency Injection.
Vehicle (Abstract)
—————————–
speed
start()
stop()
accelerate()
fuelType()
|
—————————-
Car Bike Truck
Common behavior remains in Vehicle.
Each subclass implements:
JavafuelType()
Example:
–
Car → Petrol
–
Bike → Petrol/Electric
–
Truck → Diesel
Interview Points
–
Abstract class for shared behavior.
–
Inheritance for reuse.
–
Runtime polymorphism for specialization.
Poor Design:
Vehicle
|
PetrolVehicle
|
ElectricVehicle
This creates rigid hierarchies.
Better Design:
Vehicle
|
Engine
Engine can have implementations:
Engine
|
————————
Petrol Diesel Electric
Vehicle simply contains an Engine.
Advantages:
–
Flexible.
–
Easily replace engines.
–
Better testing.
–
Follows SOLID principles.
Interview Conclusion
“Instead of inheriting behavior, I would encapsulate it in separate classes and inject the required implementation. This reduces coupling and makes the design easier to extend.”
Interview Points
–
Favor composition.
–
Loose coupling.
–
Better extensibility.
–
SOLID-compliant.
##
U. Frequently Asked Coding Questions
Expand a question to read the answer. Tick when you’re prepared (progress saved on this device).
Interview Focus
Be prepared to implement one of these approaches:
–
Eager Initialization
–
Lazy Initialization
–
Thread-safe Singleton
–
Double-Checked Locking
–
Bill Pugh Singleton (Recommended)
–
Enum Singleton (Most robust)
Interview Focus
Create multiple methods with:
–
Same method name.
–
Different parameter lists.
–
Different number, type, or order of parameters.
Interview Focus
Create a parent and child class where the child provides its own implementation of a parent method, and invoke it through a parent reference to demonstrate runtime polymorphism.
Interview Focus
Typical example:
Payment
|
—————
UPI Card Wallet
Invoke methods through the interface reference.
Interview Focus
Design:
Shape (Abstract)
|
—————————-
Circle Rectangle Triangle
Implement a common method such as:
calculateArea()
Each subclass provides its own implementation.
Interview Focus
The implementation should satisfy the Java contract:
–
Equal objects must have the same hash code.
–
Use business fields for comparison.
–
Commonly use Objects.equals() and Objects.hash().
Interview Focus
Design:
Car
|
Engine
Show that the Car delegates engine-related behavior to an Engine object instead of extending an engine class.
Interview Focus
Design:
Department
|
Employees
Show that employees can exist independently of a department and can be reassigned to another department.
- Create a Deep Copy of an object.
Interview Focus
Demonstrate that:
–
Nested objects are also copied.
–
Changes to the copied object do not affect the original.
–
Prefer copy constructors or factory methods over clone().
Interview Focus
Use:
–
this() for chaining constructors within the same class.
–
super() for chaining to the parent class constructor.
Explain that these calls must be the first statement in a constructor.
Interview Focus
Override toString() to return meaningful business information instead of the default ClassName@hashcode format.
Example output:
Employee{id=101, name=’John’, department=’IT’}
Interview Points
–
Improves debugging and logging.
–
Used automatically by System.out.println(object).
–
Provides a readable representation of the object’s state.
<button type=”button” class=”text-token-text-secondary hover:bg-token-surface-hover rounded-lg” aria-label=”Copy response”