# Abstraction

Course: [Java](https://www.devtutorials.ai/learn/java) · Section: Object-Oriented Programming
Source: https://www.devtutorials.ai/learn/java/object-oriented-programming/abstraction

> Hide details and show only what matters with abstract classes, abstract methods and interfaces, and choose between them.

Think about driving a car.

You turn the key, press the pedal and turn the wheel. You do not need to know how fuel is injected, how the gears mesh or how the brakes press the discs. The car hides all of that behind a few simple controls.

That is abstraction. You see what something does. The details of how it does it stay hidden.

In Java, abstraction means showing only the methods a user needs, and hiding the code that makes them work.

In simple words: abstraction hides the details and shows only what matters.

## What You Will Learn

In this lesson, you will learn:

1. What abstraction is, and why it makes programs simpler.
2. How to declare an abstract class, and the rules it follows.
3. How abstract methods force child classes to fill in the details.
4. How abstract classes give partial abstraction.
5. How interfaces give complete abstraction.
6. How abstraction hides implementation details.
7. When to choose an abstract class and when to choose an interface.

## Start With a Working Example

Press **Run**.

```java runnable title="The caller only knows the abstract type"
public class Main {
    public static void main(String[] args) {
        CoffeeMachine[] machines = { new EspressoMachine(), new FilterMachine() };

        for (CoffeeMachine m : machines) {
            m.makeCoffee();
            System.out.println();
        }
    }
}

abstract class CoffeeMachine {
    void makeCoffee() {
        heatWater();
        brew();
        System.out.println("Coffee is ready!");
    }

    private void heatWater() {
        System.out.println("Heating water...");
    }

    abstract void brew();
}

class EspressoMachine extends CoffeeMachine {
    @Override
    void brew() {
        System.out.println("Forcing hot water through fine coffee.");
    }
}

class FilterMachine extends CoffeeMachine {
    @Override
    void brew() {
        System.out.println("Dripping hot water through a paper filter.");
    }
}
```

Expected output:

```text
Heating water...
Forcing hot water through fine coffee.
Coffee is ready!

Heating water...
Dripping hot water through a paper filter.
Coffee is ready!
```

The loop only calls `makeCoffee()`. It never sees how the water is heated or how the coffee is brewed.

`CoffeeMachine` decides the overall steps. Each real machine only fills in its own `brew()` step.

### Try This

Add a `ColdBrewMachine` that overrides `brew()` to print `Soaking coffee in cold water overnight.` Add it to the array. The loop stays the same.

## Introduction to Abstraction

**Abstraction** means focusing on **what** an object does and hiding **how** it does it.

Everyday life is full of abstraction:

- A TV remote has buttons for "volume up". You do not see the circuit inside.
- An ATM lets you "withdraw cash". You do not see the bank's database.
- `System.out.println` prints text. You have never needed to read its code.

In Java, abstraction is built with two tools:

| Tool | Level of abstraction |
|---|---|
| Abstract class | **Partial**: some methods have bodies, some do not |
| Interface | **Complete**: describes only what, never how (apart from default methods) |

Abstraction makes programs easier to use and easier to change. Code that only depends on "what" keeps working when the "how" is rewritten.

## Abstract Classes

An **abstract class** is a class marked with the `abstract` keyword. It is an incomplete blueprint, meant to be finished by its child classes.

```text
abstract class Shape {
    ...
}
```

You cannot create an object of an abstract class directly. You create objects of its **concrete** child classes instead. A concrete class is a normal, complete class.

### Rules of Abstract Classes

1. Declare it with `abstract class`.
2. You **cannot** create an object of it with `new`.
3. It **can** have abstract methods, with no body.
4. It **can** also have normal methods, with full bodies.
5. It **can** have fields, including ones that change.
6. It **can** have constructors. They run when a child object is created, through `super(...)`.
7. A child class must override **every** abstract method, or be declared `abstract` itself.
8. It cannot be `final`, because a final class can never be extended, and an abstract class must be.

```java runnable expect-error title="You cannot create an object of an abstract class"
public class Main {
    public static void main(String[] args) {
        Shape s = new Shape();
    }
}

abstract class Shape {
    abstract double area();
}
```

The compiler reports `Shape is abstract; cannot be instantiated`.

A `Shape` variable is still allowed. It just has to point to a concrete child: `Shape s = new Circle(3);`.

## Abstract Methods

An **abstract method** is a method with **no body**. It has only a header, ending with a semicolon.

```text
abstract double area();
```

It says: "every child class must provide this method, in its own way".

Rules:

- An abstract method can only be inside an abstract class (or an interface).
- It cannot be `private`, because the child must be able to override it.
- It cannot be `static` or `final`, because those cannot be overridden.

```java runnable title="Every child must fill in the abstract methods"
public class Main {
    public static void main(String[] args) {
        Employee[] staff = {
            new FullTimeEmployee("Asha", 60000),
            new PartTimeEmployee("Ravi", 40, 500)
        };

        for (Employee e : staff) {
            e.printPayslip();
        }
    }
}

abstract class Employee {
    String name;

    Employee(String name) {
        this.name = name;
    }

    abstract int monthlyPay();

    void printPayslip() {
        System.out.println(name + " is paid " + monthlyPay() + " this month.");
    }
}

class FullTimeEmployee extends Employee {
    int salary;

    FullTimeEmployee(String name, int salary) {
        super(name);
        this.salary = salary;
    }

    @Override
    int monthlyPay() {
        return salary;
    }
}

class PartTimeEmployee extends Employee {
    int hours;
    int rate;

    PartTimeEmployee(String name, int hours, int rate) {
        super(name);
        this.hours = hours;
        this.rate = rate;
    }

    @Override
    int monthlyPay() {
        return hours * rate;
    }
}
```

Expected output:

```text
Asha is paid 60000 this month.
Ravi is paid 20000 this month.
```

`printPayslip()` is written once, in `Employee`. It calls `monthlyPay()` without knowing how pay is worked out.

Each child gives `monthlyPay()` its own body. A full-time worker gets a salary. A part-time worker is paid by the hour.

If a child forgets to override `monthlyPay()`, it does not compile. The abstract method makes sure no child can skip it.

A child class that does not override every abstract method must itself be declared `abstract`. It then cannot be instantiated either. Only a class with no missing methods can be created with `new`.

## Partial Abstraction

An abstract class gives **partial abstraction**. It hides some details and leaves others for the child classes.

- Its **normal methods** hold shared code that every child uses, like `printPayslip()`.
- Its **abstract methods** leave gaps that each child must fill, like `monthlyPay()`.
- Its **fields** hold shared data, like `name`.

Think of a form with some boxes already filled in, such as the company name and logo. Each employee only fills in the empty boxes.

Putting the overall steps in the parent, and leaving single steps to the children, is a common pattern called the **Template Method pattern**. `makeCoffee()` and `printPayslip()` both follow it.

## Complete Abstraction Using Interfaces

An interface gives **complete abstraction**. Its abstract methods describe only what a class can do. It holds no fields that change, and no constructors.

Code that depends only on an interface knows nothing about how the work is done.

```java runnable title="The shop only knows the interface, never the details"
public class Main {
    public static void main(String[] args) {
        Shop shop = new Shop(new UpiGateway());
        shop.checkout(799);

        shop = new Shop(new CardGateway());
        shop.checkout(799);
    }
}

interface PaymentGateway {
    boolean charge(int amount);
}

class UpiGateway implements PaymentGateway {
    public boolean charge(int amount) {
        System.out.println("UPI: request sent to the bank app for " + amount);
        return true;
    }
}

class CardGateway implements PaymentGateway {
    public boolean charge(int amount) {
        System.out.println("Card: checking CVV and charging " + amount);
        return true;
    }
}

class Shop {
    private PaymentGateway gateway;

    Shop(PaymentGateway gateway) {
        this.gateway = gateway;
    }

    void checkout(int total) {
        if (gateway.charge(total)) {
            System.out.println("Order confirmed.");
        }
    }
}
```

Expected output:

```text
UPI: request sent to the bank app for 799
Order confirmed.
Card: checking CVV and charging 799
Order confirmed.
```

`Shop` never mentions UPI or cards. It only knows the `PaymentGateway` interface. You can add a new gateway, such as net banking, without changing `Shop` at all.

## Hiding Implementation Details

Abstraction is not only about abstract classes and interfaces. It is also about **hiding** the parts other code does not need.

You hide details by:

- making helper methods `private`, like `heatWater()` in the first example;
- keeping fields `private`, so their layout can change freely;
- giving users one simple public method that does several steps inside.

```java runnable title="One public method hides several private steps"
public class Main {
    public static void main(String[] args) {
        EmailSender sender = new EmailSender();
        sender.send("asha@mail.com", "Your ticket is booked");
    }
}

class EmailSender {
    public void send(String to, String message) {
        connect();
        String packed = format(to, message);
        deliver(packed);
        disconnect();
    }

    private void connect() {
        System.out.println("Connecting to mail server...");
    }

    private String format(String to, String message) {
        return "To: " + to + " | " + message;
    }

    private void deliver(String packed) {
        System.out.println("Delivered -> " + packed);
    }

    private void disconnect() {
        System.out.println("Disconnected.");
    }
}
```

Expected output:

```text
Connecting to mail server...
Delivered -> To: asha@mail.com | Your ticket is booked
Disconnected.
```

The caller sees one method, `send`. The four steps inside are `private`. They can be rewritten, reordered or replaced, and the caller's code never changes.

The benefits of hiding details:

- **Simpler to use.** Callers learn one method, not four.
- **Safer to change.** Private code can change without breaking anyone.
- **Fewer mistakes.** Nobody can call `deliver()` before `connect()`.

## Abstract Classes vs Interfaces

| | Abstract class | Interface |
|---|---|---|
| Keyword to declare | `abstract class` | `interface` |
| Keyword to use | `extends` | `implements` |
| How many can a class use? | One | Many |
| Abstraction level | Partial | Complete (apart from default methods) |
| Abstract methods | Optional, marked `abstract` | Methods with no body are abstract automatically |
| Methods with bodies | Any normal methods | Only `default`, `static` and `private` methods |
| Fields | Any kind, including changing ones | Constants only |
| Constructors | Yes | No |
| Access levels on methods | Any | `public` (or `private` helpers) |
| Relationship | IS-A (`Dog` is an `Animal`) | CAN-DO (`Dog` can be `Trainable`) |

### When to Use Which

Use an **abstract class** when:

- the classes are closely related and share fields or code;
- you need a constructor or changing fields in the parent;
- you want to fix the overall steps and leave a few to the children.

Use an **interface** when:

- unrelated classes should share an ability, like `Comparable` or `Printable`;
- a class needs several abilities at once;
- you want callers to depend on "what" only, so the "how" can be swapped.

Many designs use **both**: an interface for the ability, and an abstract class that gives a helpful starting implementation of it.

**Easy Way to Remember:** an abstract class is a **half-built house**. An interface is a **checklist** of what the house must have.

## Common mistakes

The following mistakes are common when using abstract classes and methods. Each row shows what you see, why it happens and how to fix it.

| Symptom | Cause | Fix |
|---|---|---|
| `is abstract; cannot be instantiated` | `new` was used on an abstract class | Create a concrete child object |
| `does not override abstract method` | A child skipped an abstract method | Override it, or make the child `abstract` |
| `abstract methods cannot have a body` | An abstract method has `{ }` | End it with `;` instead |
| `is not abstract and does not override` on the same class | A normal class has an abstract method | Mark the class `abstract` |
| `illegal combination of modifiers` | `abstract` used with `private`, `static` or `final` | Remove the conflicting modifier |

## What to Remember

- Abstraction shows what an object does and hides how it does it.
- An abstract class cannot be instantiated. It can mix abstract methods, normal methods, fields and constructors.
- An abstract method has no body. Every concrete child must override it.
- Abstract classes give partial abstraction. Interfaces give complete abstraction.
- Hide details with `private` helpers behind one simple public method.
- Use an abstract class for close relatives that share code. Use an interface for a shared ability.

Next: Encapsulation
