Abstraction is a most important concept in object-oriented programming (OOP) that focuses on showing only the necessary information to the user while hiding unnecessary details.
In simple words, abstraction means you know what something does, but you don’t need to know how it does it.
In Java, abstraction helps developers to design flexible and secure programs by separating functionality from implementation.
Real-Life Example of Abstraction
Imagine, you are driving a car and you know how to start it using key or button and how to control it using steering. But you don’t need to understand how the engine burns fuel or how the braking system works inside.
Exactly same thing working in abstraction, it hides complex internal logic and only exposes the functionality that users need.
Benefits of Abstraction in Java
- Reduces Complexity: It simplify the programming process by focusing only on relevant operations.
- Improves Code Security: This method also hide sensitive information form the user.
- Promotes Reusability: Abstract methods and interfaces helps to provides code reusability across multiple classes.
- Enhances Maintainability: Makes it easier to update or modify code since changes to internal logic don’t affect external functionality.
How to Achieve Abstraction in Java
Java provides two main ways to achieve abstraction:
- Abstract Classes
- Interfaces
1. Abstract Classes in Java
An abstract class is a special type of class that cannot be directly created (you cannot create an object of it). It acts as a template for other classes.
An abstract class can have:
- Abstract methods → This is a methods without a body (only declared, not defined).
- Concrete methods → This methods define with full implementation.
Syntax of Abstract Class
abstract class ClassName {
abstract void methodName(); // abstract method (no body)
void normalMethod() { // concrete method
System.out.println("This is a normal method");
}
}
Example of Abstract Class
// Abstract class
abstract class Device {
abstract void turnOn(); // abstract method
void plugIn() { // concrete method
System.out.println("Device is plugged in.");
}
}
// Concrete class 1
class Fan extends Device {
void turnOn() {
System.out.println("Fan is now running.");
}
}
// Concrete class 2
class Light extends Device {
void turnOn() {
System.out.println("Light is now glowing.");
}
}
// Main class
public class Main {
public static void main(String[] args) {
Device d1 = new Fan();
d1.plugIn();
d1.turnOn();
Device d2 = new Light();
d2.turnOn();
}
}
Output:
Device is plugged in.
Fan is now running.
Light is now glowing.
- Here, The abstract class “Device” defines what every device should be able to do (turnOn).
- The subclasses (Fan and Light) define how they do it in their own way.
2. Interfaces in Java
An interface is a completely abstract structure that defines a contract, it only declares methods that must be implemented by other classes. In other words, an interface tells what a class should do, not how.
Syntax of Interface
interface InterfaceName {
void methodName(); // implicitly public and abstract
}
Click Here to read complete interface method in Java…
Mini Project: Online Payment System Using Abstraction
Let’s we create small system where users can pay using different payment methods (like UPI or Credit Card).
We’ll use abstraction to hide the internal payment logic, only the processPayment() method will be visible to the user.
Project Code
// Abstract class defining a blueprint for all payment types
abstract class Payment {
double amount;
// Constructor to set amount
Payment(double amount) {
this.amount = amount;
}
// Abstract method (must be implemented by child classes)
abstract void processPayment();
// Concrete method (common for all)
void paymentSummary() {
System.out.println("Payment of ₹" + amount + " processed successfully!");
}
}
// UPI Payment class
class UpiPayment extends Payment {
private String upiId;
UpiPayment(double amount, String upiId) {
super(amount);
this.upiId = upiId;
}
@Override
void processPayment() {
System.out.println("Processing UPI payment using ID: " + upiId);
System.out.println("Connecting to UPI server...");
System.out.println("UPI Payment Authorized!");
paymentSummary();
}
}
// Credit Card Payment class
class CardPayment extends Payment {
private String cardNumber;
CardPayment(double amount, String cardNumber) {
super(amount);
this.cardNumber = cardNumber;
}
@Override
void processPayment() {
System.out.println("Processing Card payment using card: ****" + cardNumber.substring(cardNumber.length() - 4));
System.out.println("Verifying card details...");
System.out.println("Card Payment Approved!");
paymentSummary();
}
}
// Main class to test abstraction
public class Main {
public static void main(String[] args) {
// Using abstraction: we don’t care about internal logic
Payment upi = new UpiPayment(1200.50, "rahul@upi");
Payment card = new CardPayment(3200.75, "1234567812345678");
upi.processPayment(); // Polymorphism in action
System.out.println("----------------------");
card.processPayment();
}
}
Output:
Processing UPI payment using ID: rahul@upi
Connecting to UPI server...
UPI Payment Authorized!
Payment of ₹1200.5 processed successfully!
----------------------
Processing Card payment using card: ****5678
Verifying card details...
Card Payment Approved!
Payment of ₹3200.75 processed successfully!
- Write this code logic by yourself and understand how actually this works.