Abstract Classes Revisited
Abstract Classes Revisited
You already know how to extend a class and override methods. In this lesson we step back and look at abstract classes with fresh eyes — not as a syntax curiosity, but as a design tool. By the end you will know when an abstract class is the right choice, how to mix abstract and concrete methods effectively, and what pitfalls to avoid.
What the abstract Keyword Actually Means
Placing abstract on a class does two things simultaneously:
- It forbids direct instantiation — no one can call
new Shape()ifShapeis abstract. - It allows abstract methods — method declarations with no body that subclasses must implement.
These two rules work together: you cannot create an instance of a class that has unimplemented methods, so the compiler enforces the contract.
Notice that describe() is fully implemented in the abstract class and calls area(). At runtime the call is dispatched to Circle.area(). This is the Template Method pattern in its simplest form: the base class defines the algorithm skeleton; subclasses fill in the blanks.
Abstract vs Concrete Methods — Choosing What to Provide
Every method in an abstract class is either abstract (deferred) or concrete (shared). The rule of thumb:
- Make a method abstract when each subclass genuinely needs a different implementation and there is no sensible default.
- Make a method concrete when most or all subclasses would do the same thing, or when you want to build reusable logic that calls the abstract parts.
final + template methods: Marking the orchestrating method final prevents subclasses from accidentally breaking the workflow. The abstract hook methods are what subclasses customize — the skeleton stays fixed.
Partial Implementations and Constructor Injection
Abstract classes can have constructors, fields, and any amount of concrete code. This is a key advantage over interfaces (which we cover next lesson): you can store state and reuse initialisation logic.
protected for abstract-class constructors when the class should only be constructed through subclasses. public works too (the compiler still blocks direct instantiation), but protected signals intent more clearly.
When an Abstract Class is the Right Tool
Ask yourself these questions:
- Is there a true "is-a" relationship? A
Dogis anAnimal; an abstract class models that parent type. - Do subclasses share real state? If every subclass needs a
namefield, put it in the abstract class. - Is there shared algorithm structure? Template methods shine when the steps are the same but some steps vary.
- Is single inheritance enough? A class can only extend one parent. If you need multiple types to be composed, you will need interfaces (next lesson).
Compiler Guarantees
The Java compiler enforces the abstract contract at every step:
- Trying to instantiate an abstract class is a compile error, not a runtime error.
- A subclass that does not implement all abstract methods must itself be declared
abstract. - You can hold a reference of type
ShapeorAnimal— polymorphism works normally; only instantiation is forbidden.
Summary
An abstract class is a partially implemented type that forces subclasses to complete the contract while sharing reusable code. Use it when you have a true hierarchy with shared state or behaviour, and when the template-method pattern naturally emerges. In the next lesson we introduce interfaces — a complementary (and often preferred) mechanism for expressing contracts without inheritance.