Java Abstraction
Abstraction is the process where we expose only the essential information to the user and hide its implementation portion or complex part from the user. In real word For example, in a mobile phone, we have buttons to start and end a call, but we don't need to know how the call is internally connecting the call and disconnecting it. The internal implementation is hidden from us. This is called abstraction.
In Java, abstraction can be achieved mainly using:
- Abstract classes
- Interfaces
Example:
abstract class Mobile {
abstract void makeCall();// Abstract method has no body. here only defines the specification.
void sendMessage() { // concrete method has a body
System.out.println("Message sent");
}
}
class SmartPhone extends Mobile {
@Override
void makeCall() { // Implementation of abstract method. here we define how the method works or implementation.
System.out.println("Calling through mobile network");
}
}
public class HelloWorld {
public static void main(String[] args) {
Mobile mobile = new SmartPhone();
mobile.makeCall();
mobile.sendMessage();
}
}Here: abstract void makeCall(); defines what the mobile should do that is, the specification of making a call, while SmartPhone defines the implementation of how it does it.
Advantages of Abstraction
1. Defines Rules and Specifications
It helps define the rules, structure, or specifications and tells the implementing classes to provide their own implementation.
Example:
interface Payment {
void pay(); // Rule/specification, that is every payment method must implement this method.
}
class UPI implements Payment {
@Override
public void pay() { //So here we provide the implementation of the pay() method for UPI.
System.out.println("Payment processed using UPI");
}
}
class CreditCard implements Payment {
@Override
public void pay() {//Here we provide the implementation of the pay() method for Credit Card.
System.out.println("Payment processed using Credit Card");
}
}
class PaymentTest {
public static void main(String[] args) {
Payment upiPayment = new UPI();
upiPayment.pay();// Calls the pay() method for UPI payment
Payment creditCardPayment = new CreditCard();
creditCardPayment.pay(); // Calls the pay() method for Credit Card payment
}
}Here:
- Payment defines the rule/specification: every payment method must have pay() method.
- UPI have its own way of how to implement pay().
- CreditCard also have its own way of how to implement pay().
2. Maintains Security
Abstraction helps to maintain security by hiding internal implementation details or complex portion and exposing only the nessary operations.
Example:
abstract class BankAccount {
private double balance = 10000;
private String nameOfAccountHolder;
public BankAccount(String nameOfAccountHolder) {
this.nameOfAccountHolder = nameOfAccountHolder;
}
public void withdraw(double amount, String nameOfAccountHolder) {
if (!this.nameOfAccountHolder.equals(nameOfAccountHolder)) {
System.out.println("Unauthorized access");
return;
}
if (amount <= balance) {
balance -= amount;
System.out.println("Withdrawal successful");
} else {
System.out.println("Insufficient balance");
}
}
}
BankAccount account = new SavingsAccount("John Doe");
account.withdraw(2000, "John Doe");
account.balance = 1000000; // ❌ Not allowedThe user can only use the exposed withdraw() method, where the required validation is performed by the BankAccount class itself with the account holder's name. So here, in a banking application, abstraction hides sensitive internal details such as balance and transaction processing and exposes only the required operations. This helps prevent direct access to internal sensitive data.
3. Making Easier for Code Maintain
With abstraction, we can change the internal implementation without changing the code that we use to interact with it.
Example:
interface Payment {
void pay();
}
class UPI implements Payment {
@Override
public void pay() {
//here old implementation
System.out.println("Payment processed using UPI old implementation");
}
}
class HelloWorld {
public static void main(String[] args) {
Payment payment = new UPI();
payment.pay();
}
}
After updating the implementation:
class UPI implements Payment {
@Override
public void pay() {
// here we update the implementation for UPI payment
System.out.println("Payment processed using UPI new implementation");
}
}
class HelloWorld {
public static void main(String[] args) {
Payment payment = new UPI(); //So even if we change the internal implementation of UPI, this code remains the same.
payment.pay();
}
}So, the main idea is: Abstraction allows us to change or improve the internal implementation without affecting the code that uses the functionality.
4. Supports Different Implementations
Abstraction allows different classes to implement the same functionality in their own way.
interface Payment {
void pay();
}
class UPI implements Payment {
@Override
public void pay() {
// Here we provide the implementation of the pay() method for UPI.
System.out.println("Payment processed using UPI");
}
}
class CreditCard implements Payment {
@Override
public void pay() {
// Here we provide the implementation of the pay() method for Credit Card.
System.out.println("Payment processed using Credit Card");
}
}Here, the Payment interface defines the common functionality: void pay();
But different classes provide their own implementation:
- UPI → processes payment using UPI
- CreditCard → processes payment using Credit Card
So, the calling code can work with the common Payment type:
Payment payment = new UPI();
payment.pay();
payment = new CreditCard();
payment.pay();In simple words: Abstraction allows different classes to provide different implementations of the same functionality.
Abstract Class in Java
An abstract class is a class that cannot be directly instantiated. It can contain both abstract methods (without implementation) and concrete methods (with implementation).
Example: Imagine different types of vehicles. Every vehicle should be able to start, but the way it starts can be different.
abstract class Vehicle {
// Abstract method here, no implementation provided.
abstract void start();
// Concrete method here, implementation is provided.
void stop() {
System.out.println("Vehicle stopped");
}
}
class Bus extends Vehicle {
@Override
void start() {
System.out.println("Bus starts with a key");
}
}
class Bike extends Vehicle {
@Override
void start() {
System.out.println("Bike starts with a button");
}
}Using it:
public class Main {
public static void main(String[] args) {
Vehicle bus = new Bus();
bus.start();
bus.stop();
Vehicle bike = new Bike();
bike.start();
bike.stop();
}
}Here:
- Vehicle defines the common structure.
- start() is abstract because different vehicles start differently.
- stop() contains common implementation.
- Bus and Bike provide their own implementation of start().
An abstract class is useful when multiple related classes have common data or functionality but some behavior needs to be implemented differently.
Interface in Java
An interface defines a contract or specification that forces implementing classes to follow. we can say it is fully abstract. For example, different payment methods should provide a pay() operation, but each payment method can implement it differently.
interface Payment {
void pay();
}
class UPI implements Payment {
@Override
public void pay() { //So here forced to provide implementation because of the interface contract
System.out.println("Payment made using UPI");
}
}
class CreditCard implements Payment {
@Override
public void pay() {//So here forced to provide implementation because of the interface contract
System.out.println("Payment made using Credit Card");
}
}Using it:
public class Main {
public static void main(String[] args) {
Payment payment = new UPI();
payment.pay();
payment = new CreditCard();
payment.pay();
}
}Here:
- Payment defines the contract: pay() must be implemented.
- UPI provides its implementation.
- CreditCard provides a different implementation.
The interface focuses on what should be done, rather than how it should be done.
See you in next page....🙂