Abstraction

Abstraction means hiding complex implementation details and exposing only what's necessary to use something. When you call List.add(), you don't need to know how the list resizes its internal array — you just need to know it adds an element. In Java, abstraction is achieved mainly through abstract classes and interfaces.

Abstract Classes

An abstract class is declared with the abstract keyword. It can contain a mix of:

MemberDescription
Abstract methodsDeclared with no body — every concrete subclass must provide an implementation
Regular methodsHave a full implementation, shared by all subclasses just like normal inheritance
Note: You cannot create an object of an abstract class directly with new. Trying new Shape() on an abstract Shape class is a compile error — abstract classes exist to be extended, not instantiated.

Worked Example: Shape, Circle, Rectangle

Imagine an abstract Shape class that declares an abstract area() method. Every shape has an area, but how it's calculated is completely different for a circle versus a rectangle — that calculation belongs to each specific subclass.

Example: Abstract Shape with Two Implementations

abstract class Shape {
  public abstract double area();

  public void describe() {
    System.out.println("This shape's area is " + this.area());
  }
}

class Circle extends Shape {
  private double radius;

  Circle(double radius) {
    this.radius = radius;
  }

  @Override
  public double area() {
    return Math.PI * radius * radius;
  }
}

class Rectangle extends Shape {
  private double width, height;

  Rectangle(double width, double height) {
    this.width = width;
    this.height = height;
  }

  @Override
  public double area() {
    return width * height;
  }
}

What's happening:

  • Shape declares area() as abstract — it has no body, only a signature.
  • describe() is a regular method with a real implementation, shared by every subclass without being rewritten.
  • Circle and Rectangle each provide their own area() — the calculation is completely different, but callers using a Shape reference don't need to know or care which one they have.

Using the Abstract Type

Shape c = new Circle(5);
Shape r = new Rectangle(4, 6);

c.describe(); // This shape's area is 78.53...
r.describe(); // This shape's area is 24.0
          

Each call to describe() internally calls area(), and Java resolves that call to whichever subclass's implementation actually applies — the same runtime polymorphism you saw with method overriding.

Abstraction vs. Encapsulation

These two concepts are closely related but not the same thing. Encapsulation is about hiding an object's data (fields) behind getters and setters. Abstraction is about hiding complexity — the "how" of a task — behind a simple interface, regardless of whether any data is involved. A well-designed class typically uses both together.

Next up: learn about Interfaces — Java's other, more flexible tool for abstraction.