JavaOOPbeginner
Updated:

Abstract Class vs Interface in Java: How to Choose

6 min read

A clear, side-by-side breakdown of abstract classes and interfaces — what each can hold, when to use which, and how Java 8 default methods blurred the line.

TL;DR – Quick Answer

An abstract class can hold instance state, constructors, and both abstract and concrete methods, but a class can extend only one. An interface declares a contract, allows multiple inheritance of type, and since Java 8 can carry default and static methods but never instance state. Use an abstract class for a shared base with common state and behavior; use an interface to declare a capability that unrelated classes can share.

On This Page

"Abstract class or interface?" is both a daily design decision and one of the most-asked Java interview questions, and Java 8 muddied the water by giving interfaces method bodies. This page cuts through the confusion with the one distinction that still decides it: state.

We'll compare them dimension by dimension with runnable code, then give you a decision rule you can actually apply. If you're shaky on either concept alone, read interfaces in Java and abstraction first.

The quick verdict

Use an abstract class when your subclasses are variations of one base type that share fields and common code. Use an interface when you're declaring a capability that possibly unrelated classes can each provide. When both would work, prefer the interface — it keeps your design flexible because classes can implement many of them.

Dimension Abstract class Interface
Instance fields (mutable state) Yes No (constants only)
Constructors Yes No
Method bodies Yes, always allowed Only default/static (Java 8+)
Multiple inheritance No (extend one) Yes (implement many)
Access modifiers on methods Any public (private for helpers)
Models "is-a" base type "can-do" capability

The rest of this page explains why each row is what it is, because the reasoning is what interviewers actually probe.

State: the distinction that decides everything

An abstract class can declare ordinary instance fields, so every subclass object carries that state. An interface cannot — its fields are implicitly public static final constants.

abstract class Employee {
    protected String name;      // instance state, per object
    protected double baseSalary;

    Employee(String name, double baseSalary) {  // constructor
        this.name = name;
        this.baseSalary = baseSalary;
    }

    abstract double calculateSalary();  // subclasses must define

    void printName() {                   // shared concrete behavior
        System.out.println("Employee: " + name);
    }
}

class Contractor extends Employee {
    private int hours;

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

    @Override
    double calculateSalary() {
        return baseSalary * hours;
    }
}

Employee holds name and baseSalary as real per-object state, initializes them in a constructor, and provides shared printName() behavior — none of which an interface can do. This is the situation where an abstract class is clearly right: subclasses are all kinds of Employee sharing common data.

Multiple inheritance: the interface advantage

A class extends exactly one class, but implements any number of interfaces. That's the flexibility interfaces buy you.

interface Comparable2 { int compareTo2(Object o); }
interface Serializable2 { }
interface Printable { void print(); }

class Report extends Document
        implements Comparable2, Serializable2, Printable {
    // one base type via extends, three capabilities via implements
    public int compareTo2(Object o) { return 0; }
    public void print() { System.out.println("Printing report"); }
}

Report is a Document (single base type, via extends) and can do comparison, serialization, and printing (capabilities, via implements). You could never express that with abstract classes alone, because you can't extend three of them. This is why the standard library declares Comparable, Runnable, and Serializable as interfaces — any class, regardless of its base type, can opt in.

Default methods blurred the line — but not the core

Since Java 8, interfaces can carry default methods with bodies, so "interfaces have no implementation" is no longer true.

interface Notifier {
    void send(String message);

    default void sendUrgent(String message) {   // has a body now
        send("URGENT: " + message);
    }
}

This makes interfaces feel closer to abstract classes. But two things an interface still cannot do keep them distinct:

  1. Hold mutable instance state — no per-object fields.
  2. Define a constructor — so it can't initialize such state.

That's the whole reason abstract classes survive. The moment your shared behavior needs shared data that changes per object, only an abstract class fits.

Interview note: "If interfaces have default methods, are abstract classes obsolete?" — no, and the crisp answer is: interfaces model capability and can't hold state or constructors; abstract classes model a partially-implemented base type with state and initialization. Say "state and constructors" and you've answered it. Drill this and similar traps on our Java OOP interview questions page.

Constructors and initialization

An abstract class can't be instantiated with new, but it has a constructor that runs when a concrete subclass object is created, via the super(...) chain you saw in the Contractor example. This is how it initializes its shared fields.

public class Main {
    public static void main(String[] args) {
        // Employee e = new Employee(...);      // error: abstract, can't instantiate
        Employee c = new Contractor("Ravi", 500, 20);  // fine
        c.printName();
        System.out.println(c.calculateSalary()); // 10000.0
    }
}

new Contractor(...) triggers Employee's constructor first (through super), which is exactly how the shared state gets set up — the same constructor chaining rule from ordinary inheritance.

The decision rule you can apply

When you're staring at a design choice, run these questions in order:

  1. Do the types share mutable per-object state and initialization? → Abstract class.
  2. Might unrelated classes need this capability, or does a class need it from multiple sources? → Interface.
  3. Is it purely a contract with no shared data? → Interface (default).
  4. Both seem to fit? → Prefer the interface; you can always add an abstract skeletal implementation later.

That last point is a real pattern: the JDK often ships both, like Collection (interface) plus AbstractCollection (a base class implementing the boring parts). You get the flexibility of the interface and the convenience of shared code. List and AbstractList, Map and AbstractMap follow the same design. The interface defines the contract everyone codes against; the abstract class hands subclass authors a head start by implementing the tedious methods, leaving only the essential ones abstract.

Abstract methods are the shared idea

Both tools rely on abstract methods — declared without a body, forcing subclasses to supply one. In an interface every non-default method is implicitly abstract; in an abstract class you mark them explicitly with the abstract keyword. A class with even one abstract method must itself be declared abstract and cannot be instantiated. That single rule is what guarantees a concrete subclass fills in every gap before anyone can create an object, so you never end up calling a method that has no implementation.

Common mistake: Reaching for an abstract class just to share one helper method. If there's no shared state, a default method on an interface — or a plain static utility method — is usually the cleaner choice and keeps your classes free to extend something else.

A practical example: which would you pick?

Say you're modeling shapes. Every shape has a name field and shares a describe() method, but each computes area() differently. That's shared state plus shared behavior plus abstract behavior — an abstract class (Shape).

Now say you also want some shapes to be Drawable on a canvas and some to be Exportable to a file, independent of their shape type. Those are capabilities that cut across the hierarchy — interfaces (Drawable, Exportable). A Circle then extends Shape implements Drawable. Using both together, each for what it's best at, is how experienced developers design real systems.

Where to go next

You now have the vocabulary to justify either choice in an interview and in code review. Solidify the two halves with the dedicated interfaces in Java tutorial and the abstraction overview, and see how the single-inheritance rule works in inheritance in Java.

Design judgment like this comes from building real systems and having someone review your choices — that mentorship is exactly what the Java Full Stack course provides, and the Java learning hub maps every OOP topic you'll need along the way.

Frequently Asked Questions

What is the main difference between an abstract class and an interface?
An abstract class can have instance fields, constructors, and a mix of abstract and concrete methods, and a class extends only one of them. An interface defines a contract, can be implemented by many classes at once, and cannot hold instance state. The deepest difference is state: abstract classes can carry mutable per-object data, interfaces cannot.
Since Java 8 interfaces have default methods, do we still need abstract classes?
Yes. Default methods let interfaces provide behavior, but interfaces still cannot hold instance fields or define constructors. When several subclasses need to share mutable state and initialization logic, an abstract class is the right tool. Interfaces model capability; abstract classes model a partially built base type.
Can a class extend an abstract class and implement an interface at the same time?
Yes, and this is very common. A class can extend one abstract class for shared state and behavior while implementing several interfaces to declare additional capabilities. For example, a class might extend AbstractList and implement Serializable and Comparable together.
Can an abstract class have a constructor?
Yes. Although you cannot instantiate an abstract class directly, its constructor runs when a concrete subclass object is created, through the normal super call chain. This is precisely why abstract classes can initialize shared instance state, which interfaces cannot do because they have no constructors.
When should I choose an interface over an abstract class?
Choose an interface when you are declaring a capability that unrelated classes might share, such as Comparable or Runnable, or when a class needs to inherit behavior from more than one source. Choose an abstract class when your subclasses are variations of one base type that share fields and common code. When both fit, prefer the interface for flexibility.

Want to Build Your Career in Java Full Stack with AI?

Join CodeBegun and train with working industry engineers — Explore the Program

Apply for Demo Class →
Siva Prasad Galaba
Founder, CodeBegun · Staff Engineer

Founder of CodeBegun. 15+ years building Java systems at companies like Crunchyroll. Teaches Java, Spring Boot and system design the way the industry actually works, and mentors students through projects, mock interviews and placement preparation.

Technically reviewed by CodeBegun Technical TeamLast reviewed 15 July 2026 LinkedIn
Chat with us