Java Abstraction
Table of Contents + β
In the last lesson you learned about Java polymorphism. Think about driving a car. You press the accelerator and it speeds up, and you never think about the pistons or the gearbox. Hiding complex detail and showing only what you need is the OOP idea called abstraction.
π€ What problem does abstraction solve?
Big programs get messy when every part must know how every other part works. Abstraction fixes that:
- Easy to use. The caller sees only a few simple methods.
- Easy to change. You rewrite the hidden steps without touching callers.
- Easy to share. Many different things fit one common shape, so your code treats them the same.
Think about sending a message in WhatsApp. You tap βsendβ and it goes. You never deal with network packets or servers. Abstraction draws a clean line between what (outside, simple) and how (inside, free to change).
π§© What is abstraction, really?
Abstraction means showing only the essential features and hiding the complex details.
- You are not being secretive. You remove noise so the important parts stand out.
- A TV remote shows power, volume, and channel buttons. The circuits inside stay hidden.
- A well-designed class is the same: a clean front for a complicated machine.
Java gives you two tools to build it:
- The abstract class: a partly-finished blueprint. It holds shared code and declares actions children must fill in.
- The interface: a pure list of actions, with no shared code of its own.
We focus on the abstract class here. Interfaces get their own lesson next.
π The abstract keyword and abstract methods
You build this with the abstract keyword, on the class and on any method with no body yet. An abstract method has a name and return type but no body. It ends with a semicolon, not curly braces.
- It declares what must be done.
- It does not say how to do it.
- It forces every concrete child to provide its own body.
We define a Shape that says every shape must have an area(), but not how to calculate it.
abstract class Shape { abstract double area(); // β
no body: each shape decides how
void describe() { // β
a normal shared method System.out.println("This shape has area " + area()); }}Here is what makes this work:
Shapeisabstract, andarea()has no body. It just declares that every shape must provide one.describe()is finished. Every child gets it for free.describe()callsarea()safely, because any real shape you create will have supplied anarea()body.- Written once in the base,
describe()works for every shape that ever exists.
That is the heart of an abstract class, a partly-finished blueprint: shared code all children inherit, plus abstract methods each child must complete.
You cannot create an object of an abstract class
An abstract class is incomplete by design, so you cannot write new Shape(). It exists only to be extended. Java will give you a compile error if you try to instantiate it directly. You create objects of its concrete children instead.
π‘ Filling in the details
A child class extends the abstract class and must provide a body for every abstract method. Here are two concrete shapes, each calculating area its own way.
class Circle extends Shape { double radius; Circle(double radius) { this.radius = radius; }
@Override double area() { // β
Circle's way to compute area return 3.14 * radius * radius; }}
class Rectangle extends Shape { double width, height; Rectangle(double w, double h) { this.width = w; this.height = h; }
@Override double area() { // β
Rectangle's way return width * height; }}Each child fills in area() its own way:
- Circle uses pi times radius squared.
- Rectangle uses width times height.
- Both are forced to provide it, because
Shapedeclared it abstract.
Now use them. We store two shapes in Shape variables and call the shared describe() on each.
public class Main { public static void main(String[] args) { Shape s1 = new Circle(5); Shape s2 = new Rectangle(4, 6); s1.describe(); // uses Circle's area s2.describe(); // uses Rectangle's area }}Output
This shape has area 78.5This shape has area 24.0We wrote describe() once. Each shape plugged in its own area(), and describe() used the right one automatically. That is abstraction: a shared front, each shape keeping its own way of working.
π³ A second worked example: payments
Abstraction shines in real apps too. There are many ways to pay: card, wallet, bank transfer.
- They all share one idea: βpay an amountβ.
- Each does the work differently.
- An abstract
Paymentdeclarespay()and adds a shared receipt method.
abstract class Payment { abstract void pay(double amount); // β
each method does it differently
void receipt(double amount) { // β
shared by all payment types System.out.println("Paid " + amount + ". Thank you."); }}
class CardPayment extends Payment { @Override void pay(double amount) { System.out.println("Charging card for " + amount); receipt(amount); }}
class WalletPayment extends Payment { @Override void pay(double amount) { System.out.println("Deducting " + amount + " from wallet balance"); receipt(amount); }}Now the calling code is simple. We hold each payment in a Payment variable and call pay(), without caring which kind it is.
public class Store { public static void main(String[] args) { Payment p1 = new CardPayment(); Payment p2 = new WalletPayment(); p1.pay(250.0); p2.pay(99.0); }}Output
Charging card for 250.0Paid 250.0. Thank you.Deducting 99.0 from wallet balancePaid 99.0. Thank you.The Store code knows one thing: a Payment can pay(). It does not care about cards versus wallets. Add BankTransfer extends Payment tomorrow, and the store code stays the same. Abstraction lets you add new behavior without touching the code that uses it.
βοΈ Abstraction vs encapsulation
These two are easy to mix up. Both involve βhidingβ, but they hide different things:
- Encapsulation hides the data. Private fields, access through methods. It protects state.
- Abstraction hides the complexity. Show the essential actions, tuck the messy steps away. It simplifies design.
- Encapsulation answers: how is data stored, and who can touch it?
- Abstraction answers: what does this thing do, and what can I ignore?
A good class uses both. Our Payment keeps details private (encapsulation) and exposes one simple pay() (abstraction).
β οΈ Common Mistakes
A few abstraction slip-ups to watch for.
- Trying to create an object of an abstract class. Writing
new Shape()fails to compile, because an abstract class is incomplete on purpose.
Shape s = new Shape(); // β compile error: Shape is abstractShape s = new Circle(5); // β
create a concrete child instead- Forgetting to implement an abstract method. A concrete child must provide a body for every abstract method it inherits. If it does not, the child will not compile.
class Triangle extends Shape { // β no area() body: compile error, Triangle must implement area()}
class Triangle2 extends Shape { @Override double area() { return 0.5 * 4 * 3; } // β
now it compiles}- Confusing abstraction with encapsulation. Encapsulation protects data with private fields. Abstraction hides complexity behind simple methods. Different ideas.
β Best Practices
Habits for good abstraction.
- Use an abstract class for a shared base with required behavior. Write common code once, force children to fill in the rest.
- Make a method abstract when every child must define it differently. Like
area()orpay(). If children share the code, keep it concrete. - Keep the public surface small. Expose the few essential actions. Hide the complicated steps.
- Name actions by intent, not mechanism. Call it
pay(), notchargeCardThenWriteToDatabase(). - Combine abstraction with encapsulation. Private fields give protection. A small set of methods gives simplicity.
π§© What Youβve Learned
Nicely done. Letβs recap abstraction.
- β Abstraction shows only the essential features and hides the complex details.
- β
An abstract class is a partly-finished blueprint marked with the
abstractkeyword. - β An abstract method has no body; every concrete child must implement it.
- β You cannot create an object of an abstract class; you extend it with a concrete child instead.
- β Abstraction lets you add new behavior without changing the code that uses it.
- β Encapsulation hides data; abstraction hides complexity β different goals, often used together.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What is abstraction?
Why: Abstraction exposes the essentials and hides the complicated inner workings.
- 2
What is special about an abstract method?
Why: An abstract method declares what must be done but has no body; children provide it.
- 3
Can you create an object of an abstract class?
Why: Abstract classes are incomplete, so you cannot instantiate them directly.
- 4
How does abstraction differ from encapsulation?
Why: Encapsulation protects data with private fields; abstraction hides complexity behind simple methods.
π Whatβs Next?
An abstract class can still hold shared code and fields. But sometimes you want a pure contract: just a list of methods a class must provide, with no shared code at all. That is what interfaces are for. Letβs learn them next.