00:00

Abstraction in Java – Hiding Implementation Details

Abstraction is the OOP principle of showing only what an object does and hiding how it does it. When you drive a car you use the steering wheel, pedals and gear lever; you do not need to know how fuel injection or the gearbox works. In code, callers use a simple contract, and the complex implementation stays hidden behind it.

Java supports abstraction through abstract classes and interfaces. This tutorial shows both, explains partial and full abstraction, and compares abstraction with encapsulation.

1. What Is Abstraction?

Abstraction separates two concerns:

  • The contract (what): method names, parameters and results that callers rely on.
  • The implementation (how): the code that actually does the work, which can vary and change.

Code written against the contract works with any implementation. That makes programs easier to understand, extend and test.

MechanismLevel of abstractionNotes
Abstract classPartial (0–100%)Can mix abstract methods with concrete methods, fields and constructors
InterfaceFull contract (traditionally 100%)Since Java 8 may also contain default and static methods

2. Abstraction with Interfaces

An interface defines a pure contract. Here the order service knows only that it can send a notification; whether that uses SMTP or an SMS gateway is hidden:

AbstractionWithInterface.java
import java.util.List;

public class AbstractionWithInterface {
    // The abstraction: WHAT a notifier does
    interface Notifier {
        void send(String to, String message);
    }

    // The implementations: HOW it is done (hidden from callers)
    static class EmailNotifier implements Notifier {
        public void send(String to, String message) {
            System.out.println("[SMTP] connecting... mail to " + to + ": " + message);
        }
    }
    static class SmsNotifier implements Notifier {
        public void send(String to, String message) {
            System.out.println("[SMS gateway] text to " + to + ": " + message);
        }
    }

    // Business code depends only on the abstraction
    static class OrderService {
        private final List<Notifier> notifiers;
        OrderService(List<Notifier> notifiers) { this.notifiers = notifiers; }

        void placeOrder(String customer, String item) {
            System.out.println("Order placed: " + item);
            for (Notifier n : notifiers) n.send(customer, "Your " + item + " is confirmed");
        }
    }

    public static void main(String[] args) {
        OrderService service = new OrderService(List.of(new EmailNotifier(), new SmsNotifier()));
        service.placeOrder("asha", "laptop");
    }
}
Output
Order placed: laptop
[SMTP] connecting... mail to asha: Your laptop is confirmed
[SMS gateway] text to asha: Your laptop is confirmed

Adding a WhatsAppNotifier requires no change to OrderService. In tests, you can pass a fake notifier that records messages instead of sending them.

3. Abstraction with Abstract Classes

An abstract class can provide shared code and leave specific steps abstract. This is the template method pattern:

AbstractionWithAbstractClass.java
public class AbstractionWithAbstractClass {
    // Partial abstraction: the overall algorithm is fixed, some steps are abstract
    static abstract class Report {
        // template method: the same for every report
        final void generate() {
            System.out.println("== " + title() + " ==");
            body();
            System.out.println("-- generated by JavaByTechie --");
        }
        abstract String title();     // subclasses decide
        abstract void body();
    }

    static class SalesReport extends Report {
        String title() { return "Sales Report"; }
        void body()    { System.out.println("Total sales: 1,25,000"); }
    }

    static class StockReport extends Report {
        String title() { return "Stock Report"; }
        void body()    { System.out.println("Items low on stock: 3"); }
    }

    public static void main(String[] args) {
        Report[] reports = { new SalesReport(), new StockReport() };
        for (Report r : reports) r.generate();
        // new Report();   // compile error: Report is abstract; cannot be instantiated
    }
}
Output
== Sales Report ==
Total sales: 1,25,000
-- generated by JavaByTechie --
== Stock Report ==
Items low on stock: 3
-- generated by JavaByTechie --
  • An abstract class cannot be instantiated directly.
  • An abstract method has no body; every concrete subclass must implement it.
  • Concrete methods, fields and constructors in the abstract class are shared by all subclasses.

4. Abstraction in the JDK

The Collections Framework is built on abstraction. A method that accepts Collection<Integer> works with every list, set and queue implementation:

JdkAbstraction.java
import java.util.*;

public class JdkAbstraction {
    static int total(Collection<Integer> numbers) {   // works for ANY collection
        int sum = 0;
        for (int n : numbers) sum += n;
        return sum;
    }

    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>(List.of(5, 1, 4));
        Set<Integer> set = new TreeSet<>(List.of(5, 1, 4));
        Deque<Integer> deque = new ArrayDeque<>(List.of(5, 1, 4));

        System.out.println("ArrayList total:  " + total(list));
        System.out.println("TreeSet total:    " + total(set));
        System.out.println("ArrayDeque total: " + total(deque));
    }
}
Output
ArrayList total:  10
TreeSet total:    10
ArrayDeque total: 10

Other examples: JDBC's Connection and ResultSet interfaces hide each database driver, InputStream hides whether bytes come from a file, network or memory, and ExecutorService hides thread management.

5. Abstract Class or Interface?

Use an interface when…Use an abstract class when…
Unrelated classes should share a capability (Comparable, Runnable)Closely related classes share code and state
A class needs several types (a class can implement many interfaces)You need constructors, instance fields or non-public members
You define an API that others will implementYou want to fix part of an algorithm (template method)

A common design is to combine them: an interface for the contract and an abstract class that provides a skeletal implementation, as the JDK does with List and AbstractList. See Abstract Class vs Interface.

6. Abstraction vs Encapsulation

AspectAbstractionEncapsulation
HidesImplementation complexityInternal data
FocusWhat an object doesHow access to state is controlled
Achieved withInterfaces, abstract classesPrivate fields, access modifiers, methods
Applied atDesign levelImplementation level

They complement each other: an interface abstracts behaviour, and each implementing class encapsulates its own data.

7. Benefits of Abstraction

  • Reduced complexity: callers work with a few well-named operations.
  • Loose coupling: code depends on contracts, not concrete classes.
  • Extensibility: new implementations plug in without changing existing code (open/closed principle).
  • Testability: real implementations can be replaced by test doubles.
  • Parallel development: teams agree on interfaces and implement independently.

8. Summary

  • Abstraction exposes what an object does and hides how.
  • Java achieves it with interfaces (full contracts) and abstract classes (partial abstraction).
  • Abstract classes cannot be instantiated; abstract methods must be implemented by subclasses.
  • Program to interfaces to keep code loosely coupled and easy to extend.
  • Abstraction hides complexity; encapsulation hides data.

Related Tutorials