Skip to content
Java abstraction 4 min read

Abstraction

Abstraction is the OOP principle of exposing what something does while hiding how it does it. In Java, you achieve abstraction through abstract classes and interfaces — two tools that let you define contracts your concrete classes must fulfill, keeping implementation details neatly tucked away.

Why Abstraction Matters

Think about driving a car. You press the accelerator and the car moves faster — you don’t need to know how fuel injection, pistons, and the drivetrain work together. That hidden complexity is abstraction in action.

In code, abstraction gives you:

  • Simpler interfaces — callers work with a clean API, not messy internals.
  • Flexibility — swap one implementation for another without touching the calling code.
  • Better team collaboration — one team defines the contract; another implements it.
  • Reduced coupling — your code depends on abstractions, not concrete details.

A Quick Motivating Example

Imagine you’re building a drawing app. Every shape can be drawn, but each draws itself differently.

abstract class Shape {
    // Abstract method — no body, just a contract
    abstract void draw();

    // Concrete method — shared behavior
    void describe() {
        System.out.println("I am a shape of type: " + getClass().getSimpleName());
    }
}

class Circle extends Shape {
    @Override
    void draw() {
        System.out.println("Drawing a circle 🔵");
    }
}

class Rectangle extends Shape {
    @Override
    void draw() {
        System.out.println("Drawing a rectangle 🟦");
    }
}

public class DrawingApp {
    public static void main(String[] args) {
        Shape[] shapes = { new Circle(), new Rectangle() };

        for (Shape s : shapes) {
            s.draw();       // polymorphic dispatch
            s.describe();   // inherited concrete method
        }
    }
}

Output:

Drawing a circle 🔵
I am a shape of type: Circle
Drawing a rectangle 🟦
I am a shape of type: Rectangle

The main method never knows what kind of shape it holds — it just calls draw(). That is abstraction at work.

Levels of Abstraction in Java

Java offers two mechanisms for abstraction, each with a different purpose:

FeatureAbstract ClassInterface
Can have instance fieldsYesNo (only constants)
Can have constructorsYesNo
Can have concrete methodsYesYes (default/static, Java 8+)
Multiple inheritanceNo (single)Yes (a class can implement many)
Use when…Shared base with some common codePure contract / capability definition

Tip: A good rule of thumb — if your abstraction says “is-a” with shared state, lean toward an abstract class. If it says “can-do” (a capability), lean toward an interface.

Abstraction vs Encapsulation

These two concepts are closely related but distinct:

  • Encapsulation hides data (fields) behind access modifiers and getter/setter methods. See Encapsulation.
  • Abstraction hides implementation logic behind abstract types and interfaces.

You often use them together: an abstract class may encapsulate state while abstracting behavior.

Under the Hood

When the JVM encounters a call to an abstract method (e.g., shape.draw()), it does not know at compile time which concrete implementation to invoke. Instead, it uses dynamic dispatch via the vtable (virtual method table).

Every class that overrides a method gets an entry in its vtable pointing to its specific implementation. The JVM looks up the correct method at runtime based on the actual type of the object on the heap — not the reference type declared in your code.

This is the same mechanism that powers runtime polymorphism. Abstract methods simply enforce that every concrete subclass must provide a vtable entry — the compiler refuses to instantiate an abstract class directly, guaranteeing no “missing implementation” at runtime.

For interfaces, the JVM historically used itable (interface method table) lookups, which are slightly more expensive than vtable lookups. Modern JIT compilers (like HotSpot’s C2) inline and devirtualize frequent call sites, so in hot paths the overhead disappears. See JIT Compilation for more.

Note: You cannot instantiate an abstract class with new. Attempting new Shape() when Shape is abstract causes a compile-time error, not a runtime one.

Abstraction and Design Patterns

Abstraction is the backbone of many classic design patterns:

  • Template Method — an abstract class defines the skeleton of an algorithm; subclasses fill in the steps.
  • Strategy — an interface defines interchangeable behaviors; concrete classes swap them at runtime.
  • Factory Method — an abstract factory method lets subclasses decide which concrete object to create.

Once you’re comfortable with abstract classes and interfaces, design patterns become much easier to understand. Check out Design Patterns when you’re ready.

In This Section

  • Abstract Class — Define partially-implemented base classes with abstract methods that subclasses must override.
  • Interfaces — Declare pure contracts (and default/static helpers since Java 8) that any class can implement, enabling flexible multiple-type hierarchies.
  • Abstract Class vs Interface — A side-by-side comparison to help you choose the right tool for every design decision.
  • Polymorphism — Abstraction and polymorphism work hand-in-hand; abstract types enable runtime polymorphic behavior.
  • Encapsulation — The companion OOP principle that hides data rather than implementation.
  • Inheritance — Abstract classes rely on inheritance to pass contracts down to concrete subclasses.
  • Interfaces — The other half of abstraction in Java, enabling capability-based design.
  • OOP Concepts — See how abstraction fits into the broader picture of object-oriented programming.
  • Design Patterns — Real-world patterns that use abstraction as their foundation.
Last updated June 13, 2026
Was this helpful?