Abstraction
java abstraction abstract class interface default method static functional interface dependency injection spring abstract vs interface
Introduction
In the previous lessons, you learned about Encapsulation, Inheritance, and Polymorphism. Together, these concepts help build reusable and maintainable software.
However, imagine you're designing an online payment system.
Users only need to know:
- Enter the amount
- Choose a payment method
- Click Pay
They do not need to know:
- How the payment gateway encrypts data
- How the bank verifies the transaction
- How the server communicates with third-party APIs
- How the database stores transaction records
The internal implementation is hidden from the user.
This concept is called Abstraction.
Abstraction is one of the four fundamental pillars of Object-Oriented Programming (OOP).
It focuses on hiding implementation details and exposing only the essential functionality.
Java provides abstraction through:
- Abstract Classes
- Interfaces
Abstraction is widely used in:
- Spring Boot
- Hibernate
- JDBC
- Java Collections Framework
- Microservices
- REST APIs
- Design Patterns
- Enterprise Applications
In this lesson, you'll learn:
- What is Abstraction?
- Why Abstraction is Important
- Abstract Classes
- Abstract Methods
- Concrete Methods
- Interfaces
- Default Methods
- Static Interface Methods
- Functional Interfaces
- Multiple Inheritance using Interfaces
- Dependency Injection Concepts
- Real-world Examples
- Best Practices
- Common Mistakes
- Hands-on Exercises
- Professional Interview Questions
What is Abstraction?
Abstraction is the process of hiding implementation details and exposing only the necessary functionality.
Example:
Driving a car.
The driver uses:
- Steering Wheel
- Brake
- Accelerator
- Gear
The driver does not need to understand:
- Engine combustion
- Fuel injection
- Transmission mechanics
Only the essential controls are visible.
Similarly, in Java:
User↓Interface↓Hidden Implementation
Why Abstraction?
Without abstraction:
Payment payment = new Payment();payment.connectBank();payment.encrypt();payment.verifyOTP();payment.updateDatabase();payment.generateReceipt();
With abstraction:
payment.pay();
Benefits:
- Hides complexity
- Reduces coupling
- Easier maintenance
- Better security
- Improved flexibility
- Easier testing
Abstract Class
An abstract class is a class that cannot be instantiated directly.
Example:
abstract class Animal {}
This is invalid:
Animal animal = new Animal();
Compilation Error.
An abstract class is designed to be extended.
Abstract Methods
An abstract method has no implementation.
Example:
abstract class Animal {abstract void sound();}
The child class must provide the implementation.
Implementing Abstract Methods
abstract class Animal {abstract void sound();}class Dog extends Animal {@Overridevoid sound() {System.out.println("Dog Barks");}}
Using it:
Animal animal = new Dog();animal.sound();
Output:
Dog Barks
Concrete Methods
Abstract classes can also contain fully implemented methods.
Example:
abstract class Animal {void eat() {System.out.println("Eating...");}abstract void sound();}
Child classes inherit the concrete method while implementing the abstract one.
When Should You Use an Abstract Class?
Use an abstract class when:
- Multiple classes share common code.
- Some methods have identical implementations.
- Other methods require different implementations.
- You want to provide shared state (fields).
Example:
Vehicle↓CarBusTruck
What is an Interface?
An interface defines a contract that classes agree to implement.
Example:
interface Payment {void pay();}
Implementing:
class UpiPayment implements Payment {@Overridepublic void pay() {System.out.println("UPI Payment");}}
Using:
Payment payment = new UpiPayment();payment.pay();
Output:
UPI Payment
Abstract Class vs Interface
| Abstract Class | Interface |
|---|---|
| Uses extends | Uses implements |
| Can have constructors | Cannot have constructors |
| Can have instance variables | Only constants (public static final) |
| Can contain abstract and concrete methods | Can contain abstract, default, static, and private methods (Java 9+) |
| Supports single inheritance | A class can implement multiple interfaces |
Default Methods (Java 8+)
Interfaces can provide default implementations.
interface Vehicle {default void start() {System.out.println("Vehicle Started");}}
The implementing class may use or override this behavior.
Static Methods in Interfaces
interface Calculator {static int square(int number) {return number * number;}}
Calling:
System.out.println(Calculator.square(5));
Output:
25
Functional Interfaces
A Functional Interface contains exactly one abstract method.
Example:
@FunctionalInterfaceinterface Greeting {void sayHello();}
Functional interfaces are the foundation of:
- Lambda Expressions
- Streams API
- Method References
Common examples:
RunnableCallableComparatorPredicateFunctionConsumerSupplier
Multiple Inheritance Using Interfaces
Java does not allow multiple inheritance with classes.
However:
interface Printer {void print();}interface Scanner {void scan();}class MultiFunctionPrinter implements Printer, Scanner {public void print() {System.out.println("Printing...");}public void scan() {System.out.println("Scanning...");}}
This avoids the Diamond Problem associated with multiple inheritance of classes.
Dependency Injection Concept
One of the biggest advantages of abstraction is Dependency Injection.
Example:
interface NotificationService {void send(String message);}
Implementations:
class EmailService implements NotificationService {public void send(String message) {System.out.println("Sending Email: " + message);}}class SmsService implements NotificationService {public void send(String message) {System.out.println("Sending SMS: " + message);}}
Using abstraction:
NotificationService service = new EmailService();service.send("Welcome!");
Changing to SMS requires only:
service = new SmsService();
The client code remains unchanged.
This principle is heavily used by the Spring Framework.
Real-World Example: Banking Application
abstract class Account {abstract double calculateInterest(double balance);}
Implementations:
class SavingsAccount extends Account {@Overridedouble calculateInterest(double balance) {return balance * 0.05;}}class CurrentAccount extends Account {@Overridedouble calculateInterest(double balance) {return 0;}}
Real-World Example: Payment Gateway
interface PaymentGateway {void processPayment(double amount);}
Implementations:
- RazorpayPayment
- StripePayment
- PayPalPayment
Each class provides its own implementation while exposing the same contract.
Memory Representation
Payment payment = new UpiPayment();
Memory:
Stackpayment↓Heap+---------------------------+| UpiPayment Object |+---------------------------+
Reference Type:
Payment
Actual Object:
UpiPayment
The actual implementation is selected at runtime.
Best Practices
Program to Interfaces
Prefer:
List<String> names = new ArrayList<>();
Instead of:
ArrayList<String> names = new ArrayList<>();
Use Abstract Classes for Shared State
If multiple classes share fields and common implementations, use an abstract class.
Use Interfaces for Contracts
Interfaces define capabilities that unrelated classes can implement.
Keep Interfaces Focused
Follow the Interface Segregation Principle (ISP) by designing small, purpose-specific interfaces.
Favor Composition with Abstraction
Use interfaces to reduce coupling and improve testability.
Common Mistakes
Creating Large Interfaces
Large interfaces force implementing classes to define methods they may not need.
Using Abstract Classes When No Shared Code Exists
If only behavior needs to be defined, an interface is often a better choice.
Forgetting to Implement Abstract Methods
A non-abstract subclass must implement all inherited abstract methods.
Confusing Abstraction with Encapsulation
- Abstraction hides implementation details.
- Encapsulation protects internal data.
Depending on Concrete Classes
Coding against concrete implementations reduces flexibility.
Hands-on Exercise
Create a Java program that:
- Creates an abstract class
Employeewith:- Fields:
name,employeeId - Concrete method:
displayInfo() - Abstract method:
calculateSalary()
- Fields:
- Creates
FullTimeEmployeeandContractEmployeeclasses that extendEmployee. - Creates a
NotificationServiceinterface. - Implements it using
EmailNotificationandSmsNotification. - Demonstrates runtime polymorphism using interface references.
- Adds a default method to the interface.
- Uses a functional interface with a lambda expression to print a welcome message.
Summary
Abstraction simplifies complex systems by exposing only essential functionality while hiding implementation details. Java supports abstraction using abstract classes and interfaces. Abstract classes are useful when sharing common state and behavior, whereas interfaces define contracts that enable loose coupling, multiple inheritance of type, and highly extensible enterprise applications.
Key Takeaways
- Abstraction hides implementation details and exposes essential functionality.
- Abstract classes cannot be instantiated.
- Abstract methods must be implemented by concrete subclasses.
- Interfaces define contracts for implementing classes.
- Interfaces support multiple inheritance of type.
- Default and static methods enhance interface capabilities.
- Functional interfaces enable lambda expressions.
- Programming to interfaces improves flexibility and maintainability.
- Abstraction is the foundation of Dependency Injection in frameworks like Spring.
Professional Interview Questions
1What is Abstraction in Java?
Professional Answer
Abstraction is an Object-Oriented Programming principle that hides implementation details while exposing only the essential functionality required by clients. It simplifies application design, reduces complexity, and promotes loose coupling. Java achieves abstraction through abstract classes and interfaces.
Follow-up Questions
- Which Java constructs support abstraction?
- How does abstraction improve maintainability?
Interview Tip: Remember: Abstraction = Hide the implementation, Encapsulation = Protect the data.
2What is the difference between an Abstract Class and an Interface?
Professional Answer
An abstract class is suitable when related classes need to share common state, constructors, and partially implemented behavior. An interface defines a contract that unrelated classes can implement. A class can extend only one abstract class but can implement multiple interfaces, making interfaces the preferred choice for defining capabilities and enabling loose coupling.
Follow-up Questions
- When should you choose an interface over an abstract class?
- Can an interface contain implemented methods?
Interview Tip: Use an abstract class for shared implementation and an interface for shared behavior or capabilities.
3Why are Interfaces widely used in Spring Boot?
Professional Answer
Spring Boot promotes programming to interfaces because it enables loose coupling, dependency injection, easier unit testing, and flexible implementation replacement. Client code depends on abstractions rather than concrete classes, allowing implementations to change without affecting business logic.
Follow-up Questions
- How does Dependency Injection benefit from interfaces?
- Can Spring inject multiple implementations of the same interface?
Interview Tip: Business components depend on UserService rather than UserServiceImpl — interface UserService { ... } class UserServiceImpl implements UserService { ... }