Home/Learn/Low Level Design/Interface vs Abstract Class in Java

Interface vs Abstract Class in Java

Beginner
OOP & UML Fundamentals

Understand the differences between interface and abstract class in Java 21, when to use each, and how default methods blur the historic boundary.

Overview

Interfaces and abstract classes are both abstraction mechanisms in Java, but they serve different design goals. Abstract classes model an is-a relationship in a single-inheritance hierarchy and can carry fields and constructors. Interfaces model can-do capabilities and support multiple implementation. Java 8 added default methods to interfaces, making them capable of providing implementations — blurring the historic distinction. The design rule: use an abstract class when you need to share state or a partial implementation across related types; use an interface when you want to define a contract that unrelated classes can fulfil. When both are needed, use an interface for the contract and an abstract class as the optional skeletal implementation.

Requirements Analysis

Key differences in a table: 1. Multiple inheritance: interface supports it, abstract class does not. 2. Fields: interface can only have public static final constants; abstract class can have any fields. 3. Constructors: interfaces have none; abstract classes have them. 4. Default methods: Java 8+ interfaces can have default implementations. 5. When to use: interface = capability (Flyable, Serializable); abstract class = shared base implementation (AbstractList).

Requirements
// Decision rule:
// Is-a relationship with shared state → abstract class
// Can-do capability, multiple implementations → interface
// Both needed → interface + abstract skeletal implementation (AbstractXxx)

Core Classes & Relationships

Abstract class Shape has a color field and an abstract area() method. Interface Printable has a default print() method. Interface Resizable has a resize() method. A class can extend only one abstract class but implement multiple interfaces. AbstractAnimal shows a constructor; FlyingAnimal shows an interface with a default method.

Java — enums & interfaces
// ── Abstract Class ───────────────────────────────────────────────────
public abstract class Shape {
    protected String color;      // shared state — only possible in abstract class

    public Shape(String color) { // constructor — interfaces cannot have this
        this.color = color;
    }

    public abstract double area();   // subclasses MUST implement

    public String describe() {       // concrete method — shared implementation
        return color + " shape with area " + area();
    }
}

// ── Interface with default method (Java 8+) ──────────────────────────
public interface Printable {
    default void print() {           // default — can be overridden
        System.out.println("Printing: " + this.toString());
    }
    void printDetailed();            // abstract — must implement
}

// ── Interface cannot have instance fields or constructors ────────────
public interface Dimensions {
    int DEFAULT_UNIT = 1;    // implicitly public static final — constant only
    double getWidth();
    double getHeight();
}

// ── Multiple interface implementation (not possible with abstract class) ──
public class Rectangle extends Shape implements Printable, Dimensions {
    private final double width, height;

    public Rectangle(String color, double width, double height) {
        super(color); // calls abstract class constructor
        this.width = width; this.height = height;
    }

    @Override public double area()         { return width * height; }
    @Override public void printDetailed()  { System.out.println("Rectangle " + width + "x" + height); }
    @Override public double getWidth()     { return width; }
    @Override public double getHeight()    { return height; }
    // print() is inherited from Printable default implementation
}

Java Implementation

The Template Method pattern via abstract class: AbstractLogger defines log() (template) and abstract format() (step). The skeletal implementation pattern: Collection interface + AbstractCollection (provides default implementations of most methods) so implementors only override the essential methods.

Java — core classes
// ── Template Method via abstract class ──────────────────────────────
public abstract class AbstractLogger {
    private final String name;
    protected AbstractLogger(String name) { this.name = name; }

    // Template method — final, defines the algorithm
    public final void log(String level, String message) {
        String formatted = "[" + level + "] " + name + " — " + format(message);
        write(formatted);
    }

    protected abstract String format(String message);  // subclass customises
    protected abstract void write(String formatted);   // subclass chooses output
}

public class ConsoleLogger extends AbstractLogger {
    public ConsoleLogger(String name) { super(name); }
    @Override protected String format(String msg) { return msg.toUpperCase(); }
    @Override protected void write(String fmt)    { System.out.println(fmt); }
}

// ── Skeletal implementation: interface + abstract class together ──────
// java.util.AbstractList does this for List
public interface Sortable<T> {
    int size();
    T get(int index);
    void set(int index, T value);

    default void bubbleSort(java.util.Comparator<T> cmp) {
        for (int i = 0; i < size() - 1; i++)
            for (int j = 0; j < size() - 1 - i; j++)
                if (cmp.compare(get(j), get(j+1)) > 0) {
                    T tmp = get(j); set(j, get(j+1)); set(j+1, tmp);
                }
    }
}

// Abstract class provides partial implementation
public abstract class AbstractSortableList<T> implements Sortable<T> {
    protected final List<T> data = new ArrayList<>();
    @Override public int size()            { return data.size(); }
    @Override public T get(int i)          { return data.get(i); }
    @Override public void set(int i, T v)  { data.set(i, v); }
    // Subclass adds domain-specific methods
}

// Decision summary:
// Use interface when: capability contract, multiple inheritance, unrelated classes
// Use abstract class when: shared fields/state, constructor logic, partial implementation
// Use both when: define contract in interface, provide skeletal implementation in AbstractXxx

Key Points to Remember

  • 1Interface = capability/contract; abstract class = shared base implementation with state.
  • 2Java 8 default methods let interfaces provide implementations, but they still cannot hold instance fields or constructors.
  • 3Use the skeletal implementation pattern (AbstractXxx) to minimize the effort of implementing an interface.
  • 4A class can implement multiple interfaces but extend only one abstract class — this is the primary practical difference.

Interview Questions

Sign in to ask Aria
1

When would you use an abstract class over an interface in Java?

EasyAmazon
2

What happens if a class implements two interfaces that both declare the same default method?

MediumGoogle
3

What is the skeletal implementation pattern and why does Java use it for AbstractList?

HardMicrosoft

Ask Aria about Interface vs Abstract Class in Java

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…