Abstract Classes & Abstraction
An abstract class is a half-finished blueprint: it shares real code but forces children to fill in the missing pieces.
What you will learn
- Write an abstract class with an abstract method
- Force subclasses to provide their own version
- Choose between an abstract class and an interface
A blueprint you cannot build directly
Abstraction means hiding the messy details and showing only the important idea. In Java, one tool for this is an abstract class — a class marked with the word abstract.
An abstract class is a blueprint that is deliberately unfinished. You cannot create an object from it directly. Instead, other classes extend it and complete the missing parts. It is useful when several classes share some code but each must also do one thing its own way.
Think of a form template at an office. The template has fixed parts already printed (your name goes here, the date goes here) plus blank boxes everyone must fill in themselves. You never hand in the blank template — you hand in your completed copy. An abstract class is that template: it provides the printed parts (real methods) and the blank boxes (abstract methods the child must complete).
An abstract method has no body
Inside an abstract class you can have two kinds of method. A normal method has a body (code in { }). An abstract method has no body at all — just a name ending in a semicolon. It is a promise that every child must write that method.
public abstract class Shape {
String name;
Shape(String name) {
this.name = name;
}
// abstract method: no body — each child MUST provide one
abstract double area();
// normal method: shared by every child, with real code
void describe() {
System.out.println(name + " has area " + area());
}
}Note: Output:
(No output yet — this is the blueprint. Notice area() ends in a semicolon with no curly braces: it is abstract, so Shape itself does not know how to calculate area. Each shape will. The describe() method already has real code and will be inherited as-is.)
Children fill in the blanks
Now two real shapes extend Shape. Each must write its own area(), because the parent left it abstract. They get describe() for free.
public class Circle extends Shape {
double radius;
Circle(double radius) {
super("Circle");
this.radius = radius;
}
@Override
double area() {
return 3.14159 * radius * radius;
}
}
public class Rectangle extends Shape {
double width, height;
Rectangle(double width, double height) {
super("Rectangle");
this.width = width;
this.height = height;
}
@Override
double area() {
return width * height;
}
}Note: Output:
(No output yet — these classes complete the blueprint. Each writes a real area(). If Circle had forgotten to provide area(), Java would refuse to compile, because the abstract promise was not kept.)
Using them
public class Main {
public static void main(String[] args) {
Shape[] shapes = { new Circle(2), new Rectangle(3, 4) };
for (Shape s : shapes) {
s.describe(); // shared method calls each child's own area()
}
}
}Note: Output:
Circle has area 12.56636
Rectangle has area 12.0
The inherited describe() ran for both, but each time it called the child own area(). The Circle used the radius formula and the Rectangle multiplied width by height. We could store both in a Shape[] array even though Shape can never be built on its own.
Abstract class vs interface
Both let you promise methods, but they answer different questions. Use this table to choose:
| Abstract class | Interface |
|---|---|
| Says: this IS A kind of thing (a Circle IS A Shape) | Says: this CAN DO something (a class is Playable) |
| Can hold real code AND fields/constructors | Mostly just method names (a contract) |
| A class can extend only ONE | A class can implement MANY |
| Good when children share code | Good when unrelated classes share an ability |
Watch out: You cannot write new Shape("x") — Java stops you, because an abstract class is incomplete. You can only create objects of the finished children (Circle, Rectangle). The whole point is that Shape on its own is not a real, usable thing.
Tip: A simple rule of thumb: reach for an abstract class when your children are clearly the same family and share code. Reach for an interface when you just want different, unrelated classes to share one ability.
Q. What is special about an abstract method?
✍️ Practice
- Write an abstract
Animalclass with an abstract methodsound()and a normal methoddescribe(). Extend it withDogandCat. - Try writing
new Animal()and confirm Java refuses to compile it.
🏠 Homework
- Build an abstract
Employeeclass with an abstractsalary()method and a sharedprintPayslip()method. Add two subclasses (Manager, Intern) that each compute salary differently, then loop over an array of them.