Course topics

By WebNest Studio Engineering Team

Java - Core Tutorial

Abstract Class vs Interface

Abstract classes and interfaces both support abstraction, and modern Java has narrowed the gap between them, but they still serve different design purposes. Choosing the right one is a common real-world design decision, not just a syntax choice.

The short version: an abstract class is a partly built parent class that related subclasses finish, and it can carry fields, constructors and shared code. An interface is a contract of abilities that any class can sign up to, and a class can sign up to many of them. This lesson looks at each one on its own, compares them point by point, covers the Java 8 and Java 9 changes to interfaces, and ends with the interview questions that come up most.

Why it matters

Choosing between an abstract class and an interface is a real design decision, and since Java 8 gave interfaces default methods the difference is less obvious than textbooks suggest. What still separates them is state and inheritance: an abstract class can hold fields and constructors but uses up the single extends, while a class can implement any number of interfaces.

Watch: Interface vs Abstract Class in Java: Full Difference Explained with Examples

Builds an abstract class and an interface side by side, then compares them on methods, variables, constructors and access modifiers, shows multiple inheritance through interfaces and the Java 8 default/static and Java 9 private interface methods, explains when to pick each in real projects, and finishes with the most-asked interview questions.

Watch on YouTube

What Is an Abstract Class?

An abstract class is declared with the abstract keyword and cannot be instantiated with new. It can contain abstract methods (a signature with no body, which every concrete subclass must override) alongside normal methods with full bodies, instance fields, constructors, static members and final methods. Think of it as a template: an Employee base class stores the name and rate and builds the payslip, while FullTime and Contractor each decide only how monthly pay is calculated. The constructor still matters even though you never call new Employee(...) yourself: each subclass constructor runs it through super(...) to set up the shared fields.

What Is an Interface?

An interface is declared with the interface keyword and describes what a class can do, not how it stores data. Every method declared without a body is implicitly public abstract, and every field is implicitly public static final, so it must be given a value and acts as a constant. A class signs the contract with implements and must provide a public body for each abstract method (or be declared abstract itself). Because an interface has no instance fields and no constructor, unrelated classes can share it: a CardGateway, a UpiGateway and a test stub can all be a PaymentGateway without sharing a parent class.

Side-by-Side Comparison

These are the practical differences that matter most when deciding between them.

  • Keyword: abstract class is used with extends; interface is used with implements (and an interface extends other interfaces with extends).
  • Inheritance: a class can extend only one abstract class, but can implement many interfaces.
  • Methods: an abstract class can mix abstract and concrete methods freely; an interface has abstract methods plus, since Java 8, default and static methods, and since Java 9, private methods.
  • Variables: an abstract class can hold instance and static fields of any kind, final or not; an interface can only hold implicit public static final constants.
  • Constructors: abstract classes can have constructors (called via super()); interfaces cannot have constructors at all.
  • Access modifiers: abstract class members can be public, protected, package-private or private; interface methods are public unless they are Java 9 private helpers, and nothing in an interface can be protected.
  • Initializer blocks: an abstract class can have instance and static initializer blocks; an interface can have neither.
  • Purpose: abstract classes model an "is-a" relationship with shared implementation; interfaces model a "can-do" capability contract.

Multiple Inheritance Through Interfaces

Java does not let a class extend two classes, because two parents with fields and constructors would make object state ambiguous. Interfaces carry no instance state, so a class may implement as many as it needs: a Smartphone can be both a Camera and a MusicPlayer, and it can be passed to any method that expects either type. The one conflict that can arise is two interfaces supplying a default method with the same signature. Java will not guess which one you meant: the class fails to compile until it overrides the method, and inside the override it can call a specific parent with Camera.super.describe(). If a superclass and an interface both provide the method, the class's version wins ("class wins" rule).

Java 8 and Java 9 Changes to Interfaces

Before Java 8 an interface could only declare abstract methods and constants, which made the choice easy. Three additions blurred the line.

  • default methods (Java 8): a method with a body that implementing classes inherit and may override. They exist so an interface can grow without breaking every class that already implements it; this is how Iterable.forEach() and Collection.stream() were added to existing collections.
  • static methods (Java 8): utility methods that belong to the interface itself and are called as PaymentGateway.isValid(99). They are not inherited by implementing classes.
  • private methods (Java 9): instance or static helpers that remove duplicated code between default and static methods without exposing it to implementers.
  • Even with these, an interface still cannot hold instance state or a constructor. That is the line that remains between the two.

When to Choose Which

Prefer an abstract class when related classes share meaningful common state or code and naturally belong to one hierarchy — for example, Animal as a base for Dog and Cat. Prefer an interface when unrelated classes need to promise the same capability regardless of their place in the hierarchy — for example, both a Car and a Duck can be Movable, even though they share no common ancestor otherwise.

  • Choose an abstract class for a family of closely related types that share fields and setup: an Employee base with FullTime and Contractor, or a BankAccount base with savings and current accounts.
  • Choose an interface for a capability or a pluggable service: Comparable, Runnable, a PaymentGateway with card and UPI implementations, or a repository that a test can replace with a fake.
  • Choose an interface when in doubt. It keeps the single extends free, and you can add an abstract base class later that implements it.

They Can Work Together

These two tools are not mutually exclusive. An abstract class can implement one or more interfaces and leave some or all of those interface methods unimplemented for its own subclasses to finish, combining shared base behavior with a flexible capability contract. The JDK does exactly this: List is an interface, AbstractList is an abstract class that implements most of it, and ArrayList extends AbstractList.

Common Interview Questions

  • Can an abstract class have a constructor? Yes. It runs through super(...) when a subclass object is created, even though the abstract class itself cannot be instantiated.
  • Can an interface have a constructor? No. It has no instance state to initialize.
  • Can an abstract class have no abstract methods? Yes. Marking it abstract simply prevents direct instantiation.
  • Can an abstract method be private, static or final? No. Each of those stops a subclass from overriding it, which defeats the purpose of an abstract method.
  • Can an interface extend a class? No. An interface can only extend other interfaces, and it can extend several at once.
  • Must an abstract class implement every method of an interface it implements? No. The first concrete subclass must supply whatever is still missing.
  • Why were default methods added? To add methods to existing interfaces, such as forEach() on Iterable, without breaking code that already implemented them.
  • If interfaces can have method bodies now, why keep abstract classes? Only abstract classes can hold instance state, constructors and protected members.

Examples

An abstract class: shared fields, a constructor and one method each subclass must supply

Java
public class PayrollDemo {
    public static void main(String[] args) {
        Employee[] staff = { new FullTime("Asha", 600000), new Contractor("Ravi", 120, 450) };
        for (Employee e : staff) {
            System.out.println(e.payslip());
        }
        // Employee e = new Employee("X", 0); // compile error: Employee is abstract
    }
}

abstract class Employee {
    private final String name;                 // state: instance fields are allowed
    protected final double rate;

    Employee(String name, double rate) {       // constructor runs through super(...)
        this.name = name;
        this.rate = rate;
    }

    abstract double monthlyPay();              // no body: each subclass decides

    final String payslip() {                   // shared code every subclass inherits
        return String.format("%-5s %,10.2f", name, monthlyPay());
    }
}

class FullTime extends Employee {
    FullTime(String name, double yearlySalary) {
        super(name, yearlySalary);
    }

    @Override
    double monthlyPay() { return rate / 12; }
}

class Contractor extends Employee {
    private final int hours;

    Contractor(String name, int hours, double hourlyRate) {
        super(name, hourlyRate);
        this.hours = hours;
    }

    @Override
    double monthlyPay() { return hours * rate; }
}
Output
Asha   50,000.00
Ravi   54,000.00

An interface with a constant, an abstract method, and Java 8/9 default, static and private methods

Java
public class GatewayDemo {
    public static void main(String[] args) {
        PaymentGateway card = new CardGateway();
        card.pay(500);                           // abstract method, implemented by the class
        card.payWithFee(500);                    // default method, inherited for free
        card.payWithFee(-20);
        System.out.println(PaymentGateway.isValid(99));  // static: called on the interface
        System.out.println("Fee: " + PaymentGateway.FEE_PERCENT + "%");
    }
}

interface PaymentGateway {
    double FEE_PERCENT = 2.0;                    // implicitly public static final

    void pay(double amount);                     // implicitly public abstract

    default void payWithFee(double amount) {     // Java 8: method with a body
        if (!isValid(amount)) {
            System.out.println("Rejected: " + amount);
            return;
        }
        pay(amount + fee(amount));
    }

    static boolean isValid(double amount) {      // Java 8: utility on the interface
        return amount > 0;
    }

    private double fee(double amount) {          // Java 9: helper hidden from implementers
        return amount * FEE_PERCENT / 100;
    }
}

class CardGateway implements PaymentGateway {
    @Override
    public void pay(double amount) {             // must be public
        System.out.println("Card charged " + amount);
    }
}
Output
Card charged 500.0
Card charged 510.0
Rejected: -20.0
true
Fee: 2.0%

Multiple inheritance of type, and resolving two conflicting default methods

Java
public class PhoneDemo {
    public static void main(String[] args) {
        Smartphone phone = new Smartphone();
        System.out.println(phone.describe());

        Camera cam = phone;                      // one object, several types
        MusicPlayer player = phone;
        cam.click();
        player.play();
    }
}

interface Camera {
    void click();

    default String describe() { return "Takes photos"; }
}

interface MusicPlayer {
    void play();

    default String describe() { return "Plays music"; }
}

class Smartphone implements Camera, MusicPlayer {
    @Override
    public void click() { System.out.println("Photo saved"); }

    @Override
    public void play() { System.out.println("Playing playlist"); }

    @Override
    public String describe() {                   // required: both parents have a default describe()
        return Camera.super.describe() + " and " + MusicPlayer.super.describe();
    }
}
Output
Takes photos and Plays music
Photo saved
Playing playlist

An abstract class providing shared state, implementing an interface for a capability

Java
interface Movable {
    void move();
}

abstract class Animal implements Movable {
    String name;

    Animal(String name) {
        this.name = name;
    }

    abstract String sound();
}

class Dog extends Animal {
    Dog(String name) {
        super(name);
    }

    @Override
    public void move() {
        System.out.println(name + " runs on four legs");
    }

    @Override
    String sound() {
        return "Woof";
    }
}

public class ComparisonDemo {
    public static void main(String[] args) {
        Dog d = new Dog("Rex");
        d.move();
        System.out.println(d.name + " says " + d.sound());
    }
}
Output
Rex runs on four legs
Rex says Woof

Common Mistakes

  • Choosing an abstract class purely out of habit when unrelated classes just need a shared capability — an interface fits better there.
  • Assuming interfaces cannot have any method bodies at all — default and static methods have proven this wrong since Java 8.
  • Trying to give an interface a constructor or instance field, which is not allowed under any circumstance.
  • Forgetting that a class extends only one abstract class but can implement several interfaces at once.
  • Implementing an interface method without public. Interface methods are public, so a package-private implementation fails with "attempting to assign weaker access privileges".
  • Implementing two interfaces that share a default method and not overriding it, which is a compile error until the class picks a version with Interface.super.method().
  • Calling an interface static method through an implementing class or object, such as CardGateway.isValid(5). Static interface methods are not inherited; call PaymentGateway.isValid(5).

Exercise

Model birds where every bird has a name (shared state, so an abstract class) but only some can fly (a capability, so an interface). Complete Sparrow and Penguin.

Expected output: Chirpy flies then false

Java · starter code
interface Flyable {
    String fly();
}

abstract class Bird {
    protected final String name;

    Bird(String name) {
        this.name = name;
    }
}

// TODO: class Sparrow extends Bird and implements Flyable; fly() returns "<name> flies"
// TODO: class Penguin extends Bird only

public class BirdDemo {
    public static void main(String[] args) {
        Sparrow sparrow = new Sparrow("Chirpy");
        Bird penguin = new Penguin("Pingu");
        System.out.println(sparrow.fly());
        System.out.println(penguin instanceof Flyable);
    }
}
Show hints
  • A class can do both at once: class Sparrow extends Bird implements Flyable.
  • Both subclasses need a constructor that passes the name to super(name).
Show solution
Java · solution
interface Flyable {
    String fly();
}

abstract class Bird {
    protected final String name;

    Bird(String name) {
        this.name = name;
    }
}

class Sparrow extends Bird implements Flyable {
    Sparrow(String name) {
        super(name);
    }

    @Override
    public String fly() {
        return name + " flies";
    }
}

class Penguin extends Bird {
    Penguin(String name) {
        super(name);
    }
}

public class BirdDemo {
    public static void main(String[] args) {
        Sparrow sparrow = new Sparrow("Chirpy");
        Bird penguin = new Penguin("Pingu");
        System.out.println(sparrow.fly());              // Chirpy flies
        System.out.println(penguin instanceof Flyable); // false
    }
}

Quick quiz

1. Which of the two can declare instance fields that hold state for each object?

  • A. Interface
  • B. Abstract class
  • C. Both
  • D. Neither
Show answer

B. An abstract class can have instance fields. Interface fields are always public static final constants.

2. How many abstract classes can a class extend, and how many interfaces can it implement?

  • A. One of each
  • B. Any number of both
  • C. One abstract class, any number of interfaces
  • D. Any number of abstract classes, one interface
Show answer

C. Java allows a single superclass but any number of implemented interfaces.

3. Which of the two can have a constructor?

  • A. Interface
  • B. Abstract class
  • C. Both
  • D. Neither
Show answer

B. An abstract class can declare constructors, run through super() from subclasses. An interface has no constructors.

Interview questions

When would you choose an abstract class over an interface?

Show answer

Choose an abstract class when the subclasses are closely related and share state or substantial code: common fields, a constructor that sets them, and concrete methods that all subclasses reuse. Choose an interface to describe a capability that unrelated classes may have, or when a class needs to take on several roles at once.

Now that interfaces have default methods, what can an abstract class still do that an interface cannot?

Show answer

Hold instance state and initialise it through constructors. Declare members that are protected or package-private, and methods that are final. An interface still has only constants, no constructors, and members that are public (plus private helper methods since Java 9).

Key Points to Remember

  • Abstract classes support shared state, constructors, and mixed access levels; interfaces do not.
  • A class extends one abstract class but can implement many interfaces.
  • Abstract classes model "is-a" relationships; interfaces model "can-do" capabilities.
  • Interface fields are always public static final; abstract class fields can be anything.
  • Java 8 added default and static interface methods, and Java 9 added private ones, but interfaces still have no instance state or constructors.
  • Two conflicting default methods must be resolved by overriding, using Interface.super.method() to reuse one.
  • An abstract class can implement interfaces, combining both tools in one hierarchy.

Practice in the playground

Write and run your own code for this topic, or start from the exercise or an example. Runs plain Java 17. Frameworks such as Spring, and databases, are not available here. Your code for each topic is kept in this browser.

Run the examples

Change an input, predict the result, then compare it with the output. Explain why the result changes.

WebNest Studio

Written by

WebNest Studio Engineering Team

Practical lessons from developers working with Java, Python, React, databases and production systems.

Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering