Abstraction in Java: Abstract Classes and Interfaces Explained
Learn abstraction in Java — the fourth pillar of OOP. Understand abstract classes, interfaces, when to use each, and how a class can implement many interfaces.
You've reached the fourth and final pillar of OOP: abstraction. The idea is simple and something you use every day — when you drive a car, you use the steering wheel and pedals without knowing how the engine works. The complex details are hidden; you're shown only what you need. In Java, we achieve this with abstract classes and interfaces. This lesson makes both clear, and shows you when to use each.
What is abstraction?
Abstraction means hiding the complex implementation and exposing only the essential features. It lets you define what something can do without saying how it does it — and then let each specific class fill in the "how." It's closely related to encapsulation, but at a higher level: encapsulation hides data, abstraction hides implementation detail.
Abstract classes
An abstract class is a class you can't create objects from directly — it exists to be extended. It can define abstract methods (a method with no body, just a signature) that its children are forced to implement:
abstract class Shape { // abstract method — NO body; children MUST provide one abstract double area(); // a normal method — shared by all shapes void describe() { System.out.println("This shape has area " + area()); } } class Circle extends Shape { double radius = 5; @Override double area() { return 3.14159 * radius * radius; } }
Shape s = new Circle(); // ✓ ok Shape x = new Shape(); // ✗ ERROR — can't instantiate an abstract class
The key point: Shape declares that every shape must have an area(), but leaves the actual formula to each specific shape. That's abstraction — defining the contract, deferring the detail.
Interfaces
An interface is a pure contract — a list of methods a class promises to provide, with no implementation at all. Think of it as a "can-do" capability. A class implements an interface:
interface Drawable { void draw(); // no body — just the promise } class Button implements Drawable { @Override public void draw() { System.out.println("Drawing a button"); } }
Any class that implements Drawable guarantees it has a draw() method — so your code can rely on that, whatever the actual class is. This is polymorphism at the interface level, and it's incredibly powerful for building flexible systems.
The superpower: a class can implement MANY interfaces
Here's a crucial difference. In Java, a class can only extends one parent class — but it can implements as many interfaces as you like:
class Duck extends Animal implements Swimmer, Flyer { // must provide swim() and fly() }
This lets a class mix in multiple capabilities — a Duck is an Animal that can also Swim and Fly. It's how Java gives you flexibility without the tangle that full "multiple inheritance" causes in some other languages.
Abstract class vs interface — which to use?
| Abstract class | Interface |
|---|---|
| "is-a" relationship | "can-do" capability |
| Can have fields + normal methods | Mainly method signatures (a contract) |
| Extend only ONE | Implement MANY |
| Use when classes share code | Use to define a role/ability |
A practical rule: if you have shared code to give your subclasses, lean toward an abstract class; if you're just defining a capability that unrelated classes might have, use an interface. In modern Java, interfaces are used very heavily.
Interfaces are the piece of OOP I use most in real work. This website's services are built around them — a service interface defines what operations exist, and an implementation class provides the "how." That separation means I can swap or test an implementation without touching the code that depends on it. It felt abstract (pun intended) when I first learned it, but it's the foundation of how large, maintainable Java systems — and frameworks like Spring — are built.
Key takeaways
- Abstraction hides implementation detail and exposes only what's essential.
- An abstract class can't be instantiated and can force children to implement abstract methods.
- An interface is a pure contract; classes
implementsit — and can implement many. - Abstract class = "is-a" with shared code; interface = "can-do" capability.
← Previous: Lesson 16 — Polymorphism in Java
Next: Lesson 18 — Packages & the static Keyword →