Java OOP Abstraction & Interfaces
Programming to a Contract
Story: Our application is now getting bigger. We have many implementations, but the rest of the application doesn’t need to know how each implementation works. It only needs to know what each object promises to do.
1. The Problem
Imagine a payment system.
We have:
UPI
Credit Card
Wallet
Net BankingEvery payment method needs:
pay()But the implementation is different.
UPI may communicate with a UPI system.
Credit Card may communicate with a card network.
Wallet may communicate with a wallet provider.
The caller shouldn’t need to know all of these details.
The caller simply wants:
Make the payment.
This is the problem abstraction solves.
2. What Is Abstraction?
Abstraction means:
Expose the essential concept or behavior while hiding unnecessary implementation details.
Think about a car.
You interact with:
Steering
Brake
Accelerator
GearYou don’t need to know:
Engine timing
Fuel injection
ECU logic
Transmission internalsYou use a simple interface while the complexity stays hidden.
3. Encapsulation vs Abstraction
Encapsulation
Focus:
Protect and control internal state.
private
public
protected
methodsAbstraction
Focus:
Hide unnecessary complexity and expose essential behavior.
abstract class
interfaceEasy Memory Trick
Encapsulation protects the inside.
Abstraction simplifies the outside.
4. Abstract Class
Suppose Payment is a concept rather than a concrete payment method.
We can write:
abstract class Payment {
abstract void pay();
}The abstract method:
abstract void pay();means:
A concrete Payment must provide a
pay()implementation.
5. Abstract Class Cannot Be Instantiated
This is invalid:
Payment payment = new Payment();Why?
Because an abstract class represents an incomplete/general abstraction.
But this is valid:
Payment payment = new UPIPayment();because UPIPayment is concrete.
6. Implementing an Abstract Method
class UPIPayment extends Payment {
@Override
void pay() {
System.out.println("Processing UPI payment");
}
}Another implementation:
class CardPayment extends Payment {
@Override
void pay() {
System.out.println("Processing card payment");
}
}Now:
Payment
/ \
/ \
UPI Card
pay() pay()7. Abstract Classes Can Have Normal Methods
An abstract class can contain both abstract and concrete methods.
abstract class Payment {
abstract void pay();
void printReceipt() {
System.out.println("Receipt generated");
}
}A child only needs to implement the abstract method:
class UPI extends Payment {
@Override
void pay() {
System.out.println("UPI payment");
}
}It automatically has access to:
pay()
printReceipt()8. Abstract Classes Can Have Fields
abstract class Employee {
protected String name;
protected double salary;
abstract void work();
void printDetails() {
System.out.println(name + " " + salary);
}
}Abstract classes can therefore provide shared state and shared implementation.
9. Abstract Classes Can Have Constructors
Even though we cannot create:
new Employee();the abstract class can still have a constructor.
abstract class Employee {
protected String name;
Employee(String name) {
this.name = name;
}
}When we create:
Developer d = new Developer("Amit");the parent constructor can run first.
new Developer()
↓
Employee constructor
↓
Developer constructor10. Abstract Class Mental Model
Think:
Abstract Class
│
├── Shared state
├── Constructor
├── Shared behavior
└── Required behavior
↓
abstract methodsIt is a partially implemented base abstraction.
11. Interfaces
Now suppose we don’t need shared state.
We only want to define a contract:
Any Payment must support
pay().
An interface is perfect for this.
interface Payment {
void pay(double amount);
}This defines a contract.
12. Implementing an Interface
class UPIPayment implements Payment {
@Override
public void pay(double amount) {
System.out.println("Paid using UPI");
}
}The keyword is:
implementsbecause the class is fulfilling the interface contract.
13. extends vs implements
class Developer extends Employeemeans:
Developer inherits from Employee.
class UPI implements Paymentmeans:
UPI agrees to fulfill the Payment contract.
Remember:
class → extends class
class → implements interface
interface → extends interface14. Interface as a Contract
Think of:
interface Flyable {
void fly();
}as saying:
If you claim to be Flyable, you must provide
fly().
Then:
class Bird implements Flyable {
@Override
public void fly() {
System.out.println("Bird flying");
}
}and:
class Airplane implements Flyable {
@Override
public void fly() {
System.out.println("Airplane flying");
}
}Bird and Airplane don’t need to share the same class hierarchy.
They simply share a capability:
CAN-FLY15. Interface Polymorphism
Now:
Payment payment = new UPIPayment();The reference type is:
PaymentThe actual object is:
UPIPaymentThen:
payment.pay(1000);executes:
UPIPayment.pay()This is polymorphism through an interface.
16. Why Use an Interface Reference?
Compare:
UPIPayment payment = new UPIPayment();with:
Payment payment = new UPIPayment();The second says:
I don’t care about the concrete implementation. I care only that this object follows the Payment contract.
This reduces coupling.
17. Programming to an Abstraction
Instead of:
class CheckoutService {
private UPIPayment payment;
}we can write:
class CheckoutService {
private Payment payment;
CheckoutService(Payment payment) {
this.payment = payment;
}
}Now the service can work with:
UPI
Card
Wallet
Net Bankingwithout changing the service itself.
Get Amit Kumar’s stories in your inbox
Join Medium for free to get updates from this writer.
This is called:
Programming to an abstraction/interface rather than a concrete implementation.
18. Loose Coupling
If a class depends directly on:
UPIPaymentit is tightly coupled to that implementation.
If it depends on:
Paymentit depends on an abstraction.
Concrete implementation
↓
Higher couplingInterface / abstraction
↓
Lower couplingThis idea becomes extremely important in Spring Boot.
19. Multiple Interfaces
Java doesn’t allow:
class C extends A, BBut it allows:
class Duck implements Flyable, Swimmable {
}Example:
interface Flyable {
void fly();
}
interface Swimmable {
void swim();
}
class Duck implements Flyable, Swimmable {
@Override
public void fly() {
System.out.println("Flying");
}
@Override
public void swim() {
System.out.println("Swimming");
}
}So one class can have:
one parent class
+
multiple capabilities20. Interface Inheritance
An interface can extend another interface.
interface Animal {
void eat();
}
interface Pet extends Animal {
void play();
}Then:
class Dog implements Pet {
@Override
public void eat() {
}
@Override
public void play() {
}
}The class fulfills both contracts.
21. Abstract Class vs Interface
Abstract Class
Best thought of as:
Shared base abstraction
Can contain:
instance fields
constructors
concrete methods
abstract methodsExample:
Employee
├── name
├── salary
├── printDetails()
└── work()Interface
Best thought of as:
Contract or capability
Examples:
Payment
Flyable
Runnable
Comparable
SerializableA class can implement multiple interfaces.
22. Abstract Class vs Interface Table
FeatureAbstract ClassInterfaceAbstract methodsYesYesConcrete methodsYesYes, through modern interface featuresInstance fieldsYesNoConstructorsYesNoInstance stateYesNoMultiple class inheritanceNoA class can implement multiple interfacesClass usesextendsimplementsMain purposeShared base abstractionContract/capability
23. Simple Mental Rule
A useful starting point:
Abstract Class
↓
IS-A
↓
Shared baseInterface:
Interface
↓
CAN-DO
↓
Capability / contractThis isn’t an absolute rule, but it’s a very useful design intuition.
24. Default Methods
Modern Java interfaces can contain default implementations.
interface Payment {
void pay();
default void printReceipt() {
System.out.println("Receipt generated");
}
}An implementing class:
class UPI implements Payment {
@Override
public void pay() {
System.out.println("UPI payment");
}
}can use:
UPI payment = new UPI();
payment.pay();
payment.printReceipt();The class inherits the default implementation.
25. Why Were Default Methods Added?
Imagine an interface already has hundreds of implementations.
If a new abstract method were added:
void printReceipt();all existing implementations would need to implement it.
Default methods allow interfaces to evolve while providing a default implementation.
26. Static Interface Methods
Interfaces can also contain static methods.
interface Payment {
static void validateAmount(double amount) {
System.out.println("Validating amount");
}
}Call it through the interface:
Payment.validateAmount(1000);It belongs to the interface itself.
27. Interface Fields
Interface fields are implicitly:
public
static
finalExample:
interface Payment {
int MAX_RETRIES = 3;
}Conceptually:
public static final int MAX_RETRIES = 3;The value cannot be reassigned.
28. The Complete OOP Story
We can now connect everything.
Step 1 — Class
We define the structure and behavior of an object.
Class
↓
BlueprintStep 2 — Object
We create an actual instance.
Object
↓
Actual thingStep 3 — Constructor
We initialize the object.
Constructor
↓
Initial stateStep 4 — Encapsulation
We protect internal state.
private
↓
Controlled accessStep 5 — Inheritance
We create specialized types.
Employee
↓
DeveloperStep 6 — Overriding
A child provides specialized behavior.
Employee.work()
↓
Developer.work()Step 7 — Polymorphism
One reference can represent different implementations.
Employee employee = new Developer();Step 8 — Abstraction
We stop caring about unnecessary implementation details.
Payment
↓
pay()Step 9 — Interface
We express a contract.
interface Payment {
void pay();
}Now:
UPI
Card
Walletcan all implement the same contract.
29. The Complete OOP Mental Model
OOP
│
┌─────────────────┼─────────────────┐
↓ ↓ ↓
CLASS OBJECT REFERENCE
│ │ │
Blueprint Instance Points to
│ │ │
└─────────────────┼─────────────────┘
↓
CONSTRUCTOR
│
↓
this
│
↓
ENCAPSULATION
│
↓
private state
│
↓
INHERITANCE
│
↓
IS-A
│
↓
OVERRIDING
│
↓
POLYMORPHISM
│
┌───────────┴───────────┐
↓ ↓
Reference Type Actual Object
↓ ↓
What can I access? Which override runs?
│
└───────────┬───────────┘
↓
ABSTRACTION
│
┌────────┴────────┐
↓ ↓
Abstract Class Interface
↓ ↓
Shared Base Contract
│
↓
Loose Coupling30. The Most Important Pattern
Whenever you see:
Payment payment = new UPIPayment();think:
Payment
↓
Abstraction / ContractUPIPayment
↓
Concrete Implementationpayment
↓
Referencenew UPIPayment()
↓
Actual Objectpayment.pay()
↓
Polymorphism
↓
UPIPayment.pay()
This single pattern connects:
Abstraction
+
Interface
+
Polymorphism
+
Loose CouplingQuick Revision
Abstraction
Hide unnecessary implementation details and expose essential behavior.
Abstract class
Partially implemented base abstraction.
Interface
Contract/capability that classes can implement.
extends
Class inheritance or interface inheritance.
implements
Class fulfills an interface contract.
Default method
Interface method with a default implementation.
Interface field
Implicitly
public static final.
Loose coupling
Depending on abstractions rather than concrete implementations.
Programming to an interface
Write code against the contract rather than a specific implementation.
Key mental model
Abstract Class
→ Shared baseInterface
→ Contract / capabilityPolymorphism
→ Multiple implementations behind one abstraction









