Abstraction in Java β Abstract Classes and Interfaces
Abstraction is the practice of exposing what something does while hiding how. In Java it takes two forms: abstract classes (partial implementation) and interfaces (pure contract, plus default methods since Java 8).
Abstract class
public abstract class Shape {
private final String id = UUID.randomUUID().toString(); // shared state
public String id() { return id; } // shared behaviour
public abstract double area(); // each subclass must provide
}
public class Circle extends Shape {
private final double r;
public Circle(double r) { this.r = r; }
@Override public double area() { return Math.PI * r * r; }
}
- Can have fields (state).
- Can have constructors.
- Subclasses extend with
extendsβ only one parent.
Interface
public interface Shape {
double area(); // abstract (implicit)
default boolean isLarge() { // default method β Java 8+
return area() > 100;
}
static Shape zero() { // static β Java 8+
return () -> 0.0;
}
}
public class Square implements Shape {
private final double s;
public Square(double s) { this.s = s; }
public double area() { return s * s; }
}
- Only
public static finalfields (constants). - No constructor.
- A class implements any number with
implements.
When to use which
| Use abstract class when | Use interface when |
|---|---|
| You want to share state and partial implementation. | You want a pure contract. |
| Subclasses are clearly related (is-a Shape). | Implementers are diverse (Shape, Animal, Serialisable). |
| You need constructors or non-public methods. | You need multiple inheritance. |
Sealed types (Java 17+)
public sealed interface Result<T> permits Ok, Err {}
public record Ok<T>(T value) implements Result<T> {}
public record Err<T>(String e) implements Result<T> {}
String msg = switch (result) {
case Ok<?> o -> "ok " + o.value();
case Err<?> e -> "err " + e.e();
// no default β compiler knows the hierarchy is closed
};
Common mistakes
- Abstract class with a single concrete subclass β often a sign that you should just use a normal class.
- Interface with a single implementation and no other use β premature abstraction. Add the interface when you actually need a second implementation.
- Protected fields in an abstract class β leaks internals to subclasses. Expose via protected methods.
Related
Pillar: OOP in Java. Siblings: interfaces, sealed classes, abstract keyword.