Abstraction in Java
By the Syncfusion DevTutorials team · Last updated
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:
- What abstraction is, and why it makes programs simpler.
- How to declare an abstract class, and the rules it follows.
- How abstract methods force child classes to fill in the details.
- How abstract classes give partial abstraction.
- How interfaces give complete abstraction.
- How abstraction hides implementation details.
- When to choose an abstract class and when to choose an interface.
Start With a Working Example
Press Run.
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:
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.printlnprints 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.
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
- Declare it with
abstract class. - You cannot create an object of it with
new. - It can have abstract methods, with no body.
- It can also have normal methods, with full bodies.
- It can have fields, including ones that change.
- It can have constructors. They run when a child object is created, through
super(...). - A child class must override every abstract method, or be declared
abstractitself. - It cannot be
final, because a final class can never be extended, and an abstract class must be.
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.
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
staticorfinal, because those cannot be overridden.
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:
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.
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:
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, likeheatWater()in the first example; - keeping fields
private, so their layout can change freely; - giving users one simple public method that does several steps inside.
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:
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()beforeconnect().
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
ComparableorPrintable; - 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
privatehelpers behind one simple public method. - Use an abstract class for close relatives that share code. Use an interface for a shared ability.
Next: Encapsulation