00:00

Difference Between Abstract Class and Interface in Java

Both abstract classes and interfaces let you define methods that subclasses must implement, and neither can be instantiated directly. They serve different purposes, though:

  • An abstract class is a partially implemented base class for closely related classes. It can hold state (fields), constructors and code shared by its subclasses. A class can extend only one.
  • An interface is a contract or capability that any class can adopt, whatever its hierarchy. It has no instance state, and a class can implement many.

Since Java 8 interfaces can contain default and static methods, which narrowed the gap, but the key differences remain. This page compares them in detail with examples.

1. Comparison Table

AspectAbstract classInterface
Keywordabstract class; used with extendsinterface; used with implements
Multiple inheritanceA class extends only one classA class implements any number; an interface can extend many
MethodsAbstract and concrete methodsAbstract, default (8), static (8) and private (9) methods
FieldsAny: instance, static, final or mutableOnly public static final constants
ConstructorsYesNo
Access modifiersAny (private, protected…)Members are public (private helper methods allowed)
StateCan hold per-object stateStateless
Relationship"is-a" (strong, same family)"can-do" / capability (any class)
LambdasCannot be a lambda targetFunctional interfaces can
EvolutionAdding a concrete method is safeAdding an abstract method breaks implementers (use default)

2. Both in One Example

Employee is an abstract class with a name, a constructor and shared code; Payable and Auditable are interfaces that unrelated types can implement:

AbstractVsInterface.java
public class AbstractVsInterface {
    // Interface: a capability any class can have
    interface Payable {
        double amount();
        default String receipt() { return String.format("Paid %.2f", amount()); }  // Java 8 default
    }

    interface Auditable { String auditTag(); }

    // Abstract class: shared state + constructor + partial implementation
    static abstract class Employee {
        protected final String name;
        private static int count;

        Employee(String name) { this.name = name; count++; }       // constructor
        abstract double monthlyPay();                                // must be implemented
        String describe() { return name + " earns " + monthlyPay(); }
        static int count() { return count; }
    }

    // One superclass, many interfaces
    static class Manager extends Employee implements Payable, Auditable {
        Manager(String name) { super(name); }
        double monthlyPay() { return 150_000; }
        public double amount() { return monthlyPay(); }
        public String auditTag() { return "MGR-" + name.toUpperCase(); }
    }

    // An unrelated class can be Payable too
    record Invoice(String id, double amount) implements Payable { }

    public static void main(String[] args) {
        Manager m = new Manager("Asha");
        System.out.println(m.describe());
        System.out.println(m.receipt() + " | " + m.auditTag());

        Payable[] bills = { m, new Invoice("INV-7", 4999.5) };     // same contract, different hierarchies
        for (Payable p : bills) System.out.println(p.getClass().getSimpleName() + ": " + p.receipt());
        System.out.println("Employees created: " + Employee.count());
    }
}
Output
Asha earns 150000.0
Paid 150000.00 | MGR-ASHA
Manager: Paid 150000.00
Invoice: Paid 4999.50
Employees created: 1
  • Manager extends one class but implements two interfaces.
  • Invoice is a record, not an employee, yet it is Payable too: interfaces cut across hierarchies.
  • The default method receipt() is shared by every Payable without a common superclass.

3. Using Them Together: Skeletal Implementation

The choice is often not either/or. A common design defines the type as an interface and provides an abstract class that implements the boring parts, exactly as the JDK does with List and AbstractList:

SkeletalImplementation.java
public class SkeletalImplementation {
    interface Shape {                       // the contract (type)
        double area();
        String name();
    }

    static abstract class AbstractShape implements Shape {   // reusable partial implementation
        private final String name;
        AbstractShape(String name) { this.name = name; }
        public String name() { return name; }
        @Override public String toString() { return String.format("%s (area %.2f)", name, area()); }
    }

    static class Circle extends AbstractShape {
        private final double r;
        Circle(double r) { super("Circle"); this.r = r; }
        public double area() { return Math.PI * r * r; }
    }

    static class Square extends AbstractShape {
        private final double s;
        Square(double s) { super("Square"); this.s = s; }
        public double area() { return s * s; }
    }

    public static void main(String[] args) {
        Shape[] shapes = { new Circle(1.5), new Square(3) };
        for (Shape s : shapes) System.out.println(s);
    }
}
Output
Circle (area 7.07)
Square (area 9.00)

Clients depend on Shape; implementers can extend AbstractShape for convenience or implement Shape directly.

4. When to Use Which

Choose an interface when…Choose an abstract class when…
You define a capability for unrelated classes (Comparable, Runnable, AutoCloseable)Closely related classes share code and fields
A class needs several types at onceYou need constructors or non-public members
You want lambdas (functional interface)You want a template method that fixes an algorithm's structure
You publish an API others will implementYou control all subclasses and want to share state

A good default: start with an interface, and add an abstract class only when implementations need to share state or substantial code.

5. What Changed in Java 8 and Later?

  • Java 8: default and static methods in interfaces, so interfaces can carry behaviour and evolve safely.
  • Java 9: private interface methods for sharing code between defaults.
  • Java 17: both abstract classes and interfaces can be sealed to restrict their implementations.

Interfaces still cannot have instance fields or constructors, which is the main reason abstract classes remain useful.

6. Summary

  • Abstract classes share state and code among related classes; a class can extend only one.
  • Interfaces define contracts any class can implement; a class can implement many.
  • Abstract classes have constructors and any fields; interfaces have only constants.
  • Combine them: interface for the type, abstract class for a skeletal implementation.

Related Tutorials