Java Abstract Classes
Define partial implementations in Java with abstract classes and methods that subclasses must complete.
An abstract class is a class that can't be instantiated directly. It exists to be extended. It can mix concrete methods (with bodies) and abstract methods (no body, the subclass has to write them) — that combination is what makes it different from both a regular class and an interface.
Use an abstract class when concrete subclasses need to share state and infrastructure, not just an API contract. If all you need is a contract, an interface is the better fit.
Declaring one
Add abstract to the class header. Add abstract to any method that has no body:
public abstract class Shape {
protected final String name;
protected Shape(String name) { this.name = name; }
public abstract double area(); // no body — subclass must provide one
public String describe() { // concrete — inherited as-is
return name + " area=" + area();
}
}A few things follow from this:
new Shape("circle")is a compile error — abstract classes cannot be instantiated.- A subclass that doesn't implement every inherited abstract method must itself be declared
abstract. You can have abstract subclasses of abstract classes. - An abstract class can have a constructor — subclasses call it with
super(...)just like a regular parent.
Implementing the abstract methods
A concrete subclass must supply a body for every inherited abstract method:
public class Circle extends Shape {
private final double r;
public Circle(double r) {
super("circle");
this.r = r;
}
@Override
public double area() { return Math.PI * r * r; }
}Now new Circle(2) works, and describe() (inherited from Shape) calls back into the subclass's area() via dynamic dispatch.
Abstract classes can hold state
This is the main reason to pick an abstract class over an interface. The parent can declare fields, write a constructor that initializes them, and offer methods that operate on that shared state:
public abstract class HttpHandler {
private final String path;
protected HttpHandler(String path) { this.path = path; }
public final String path() { return path; }
public abstract Response handle(Request r); // subclass-specific behavior
}Every concrete handler has a path; the parent stores it and exposes it; each subclass only writes the per-request logic. Interfaces can't do this on their own (they have no instance fields).
Mixing abstract and concrete methods — the template method
A common pattern: the abstract class implements the overall flow as a concrete method and leaves the variation points abstract. Subclasses fill in just the parts that differ:
public abstract class Beverage {
// Template — the algorithm, written once.
public final void prepare() {
boilWater();
brew(); // varies
pourIntoCup();
addCondiments(); // varies
}
protected abstract void brew();
protected abstract void addCondiments();
private void boilWater() { System.out.println("boiling water"); }
private void pourIntoCup() { System.out.println("pouring into cup"); }
}
public class Tea extends Beverage {
protected void brew() { System.out.println("steeping tea"); }
protected void addCondiments() { System.out.println("adding lemon"); }
}Tea.prepare() runs the parent's template, which calls back into Tea's brew and addCondiments via polymorphism. Adding a Coffee subclass needs only the two abstract methods.
This is the template method pattern and is the single most common reason to choose an abstract class.
Abstract vs final
abstract and final are opposites and the compiler enforces it:
abstract class— must be subclassed.final class— must not be subclassed.
Same for methods: abstract methods must be overridden; final methods cannot be. Writing both at once is a compile error.
Abstract vs interface
| Abstract class | Interface | |
|---|---|---|
| Constructors | Yes | No |
| Instance fields | Yes | No (only public static final constants) |
| Method bodies | Yes (any number) | Yes via default (intended sparingly) |
| Inheritance | Single — one parent class only | Multiple — many interfaces |
| Use when | Subclasses share state and infrastructure | Subclasses only share an API contract |
A practical rule of thumb: start with an interface. Upgrade to (or add) an abstract class only if you find shared code accumulating across implementations. Java 8+ default methods on interfaces have eaten into some of the territory abstract classes used to own, but the "shared mutable state" use case is still abstract-class country.
Abstract methods cannot be private or static
privatewould make the method invisible to subclasses — they couldn't override it, so the abstractness would be unenforceable.staticmethods aren't dispatched dynamically — they can't be overridden, only hidden — so an abstract static method would be meaningless.
These two combinations are compile errors.
A worked example
What's next
You've now seen the version of abstraction that comes bundled with state and shared code. The version that ditches both — pure contract, no implementation — is the interface. Continue to Java interfaces.
Practice
A class extends an abstract class but does not implement all of its abstract methods. What happens?