skip to content

What are the core differences between an interface and an abstract class in Java, and when would you reach for each?

level: juniorimportance: must knowfreq 88%

answer

  1. implements many vs extends one
  2. interface = contract/type; abstract class = partial base with state
  3. interfaces have no instance fields, no constructors
  4. is-a family + shared state -> abstract class; capability/role -> interface
  5. default methods blur it; state + constructors don't

basics

~20 s

An interface describes what a class can do (a contract of methods); an abstract class is a partly-finished base class you extend. A class can implement many interfaces but extend only one class. Use an interface for a capability shared by unrelated types; use an abstract class when subclasses share state and code.

solid answer

~50 s

An interface is a pure type/contract: it lists method signatures (plus default/static/private methods and public-static-final constants) but holds no instance state. A class can implement many interfaces, giving Java multiple inheritance of type. An abstract class is an incomplete base in a single-inheritance hierarchy: it can have instance fields, constructors, any access modifier, and a mix of concrete and abstract methods, so it shares both state and implementation with its subclasses. Reach for an interface when a capability (Comparable, Runnable) is shared by otherwise-unrelated classes, or when you want to keep the door open for implementers to extend something else. Reach for an abstract class when subclasses are genuinely an 'is-a' family that share fields and partial implementation, and you want one controlled place for that common code. Modern Java blurs the line via default methods, but only abstract classes carry per-instance state.

code

java · 22 lines
java
interface Drawable {            // a contract: 'can be drawn'
    void draw();                // implicitly public abstract
    default void redraw() {     // shared behavior, since Java 8
        draw();
    }
}

abstract class Shape {          // a partial base WITH state
    protected final String name; // per-instance field — interfaces can't have this
    protected Shape(String name) { this.name = name; } // constructor
    abstract double area();     // subclasses must fill this in
    String describe() { return name + " area=" + area(); } // shared code
}

// One class can extend ONE class but implement MANY interfaces:
class Circle extends Shape implements Drawable, Comparable<Circle> {
    private final double r;
    Circle(double r) { super("circle"); this.r = r; }
    double area() { return Math.PI * r * r; }
    public void draw() { /* ... */ }
    public int compareTo(Circle o) { return Double.compare(area(), o.area()); }
}

go deeper

for a junior

Knows the headline rules: implement many interfaces, extend one class; interface = contract of methods, abstract class = base you can't instantiate. Can give a simple 'use interface for a capability, abstract class for shared code' guideline.

for a middle

Articulates that only abstract classes hold instance state and constructors, that interfaces give multiple inheritance of type, and that default methods exist since Java 8. Picks the right tool for concrete scenarios and explains why.

for a senior

Reasons about design trade-offs: programming to an interface for decoupling, single-inheritance cost, and combining both via the interface-plus-skeletal-abstract-class pattern (Collection/AbstractCollection). Discusses default-method conflict resolution.

for a principal

Frames the choice in API-evolution and coupling terms: interfaces as stable published contracts that can grow via default methods without breaking implementers, abstract classes as a versioning liability and single-inheritance commitment. Weighs composition over inheritance and library-boundary stability.

## The two tools **A class** in Java is a blueprint for objects: it has *fields* (per-object data, also called instance state), *methods* (behavior), and *constructors* (code that runs when an object is created). **Inheritance** lets one class reuse another with `class Dog extends Animal` — `Dog` is then a *subclass* and `Animal` a *superclass*. Java allows **single inheritance of implementation**: a class may `extends` exactly one class. **An abstract class** is a class marked `abstract` that *cannot itself be instantiated* (you cannot write `new Animal()`), because it is deliberately incomplete. It may declare **abstract methods** — methods with a signature but no body, e.g. `abstract double area();` — that every concrete (non-abstract) subclass must implement. It may *also* contain ordinary fields, constructors, and fully-written (concrete) methods. So it is a *partially-built base* that hands finished pieces and shared data to its subclasses while forcing them to fill in the gaps. **An interface** is a separate construct (`interface Drawable { ... }`) that describes a **contract** — a set of method signatures a class promises to provide. A class adopts it with `class Circle implements Drawable`. Historically an interface could only hold abstract method signatures and constants. Since Java 8 it can also have **default methods** (a method with a body, marked `default`, that implementers inherit but may override) and **static methods**; since Java 9, **private** methods to share logic between defaults. Crucially, an interface holds **no instance state** — any field declared in an interface is implicitly `public static final` (a shared constant), never per-object data. ## The decisive differences 1. **Inheritance count.** A class can `implements` *many* interfaces but `extends` only *one* class. This is Java's split: **multiple inheritance of type** (via interfaces) but **single inheritance of implementation** (via classes). If a type might need to be several things at once, those things must be interfaces. 2. **State.** Only abstract classes can hold per-instance fields (e.g. a `protected String name`). Interfaces cannot — their only fields are constants. So if subtypes must share *mutable data*, that belongs in an abstract class. 3. **Constructors.** Abstract classes have constructors (called via `super(...)` when a subclass is built, to initialize the shared fields). Interfaces have none — you never construct an interface. 4. **Access modifiers.** Abstract-class members can be `private`, `protected`, package-private, or `public`. Interface members are effectively `public` (methods are implicitly `public abstract` or `public default`); you cannot have a `protected` interface method. 5. **Default-method conflicts.** When a class implements two interfaces that both provide a default method with the same signature, the compiler forces the class to override it and resolve the ambiguity (often via `Interface.super.method()`). Abstract classes don't create this 'diamond' because there's only one superclass. ## How to choose - Choose an **interface** when: the thing you're modelling is a **capability or role** that unrelated classes may share (`Comparable`, `Serializable`, `Runnable`); when implementers should stay free to extend some *other* base class; or when you want a small, stable contract that many providers fulfil. Interfaces are the backbone of *programming to an interface*, which decouples callers from concrete implementations. - Choose an **abstract class** when: subtypes form a real **is-a family** that shares **fields and partial implementation**; when you want one controlled, non-public place for common code; or when you need a constructor to enforce invariants on shared state. This is the classic **Template Method** shape — the abstract class writes the algorithm skeleton and leaves *hook* methods abstract for subclasses (e.g. `AbstractList` in the JDK). ## The pragmatic modern answer Since default methods exist, the line is blurrier: you *can* ship behavior in an interface. But the two enduring discriminators remain: **interfaces give multiple inheritance of type**, and **only abstract classes carry per-instance state and constructors**. A common, robust pattern is to combine them — publish an **interface** as the public contract and offer an **abstract skeletal implementation** (e.g. `Collection` + `AbstractCollection`) so implementers get the best of both. Default to an interface for the contract; introduce an abstract class only when shared state or substantial shared implementation justifies the single-inheritance cost.

  • Since Java 8 added default methods, can an interface fully replace an abstract class?
    No. Default methods let an interface ship behavior, but an interface still cannot declare per-instance fields or constructors — it holds no object state. If subtypes must share mutable data or run initialization logic, you still need an abstract class. Interfaces also can't have protected/private-instance members (private methods are only helpers for defaults).
  • If a class needs behavior from two different sources, how do interfaces and abstract classes constrain you?
    You can implement both as interfaces and get all their (default) behavior, because a class implements unlimited interfaces. But you can extend only one abstract class, so two abstract bases can't both be inherited — you'd have to pick one and re-express the other as an interface or via composition.

An interface is a job description ('must be able to fly') that any creature — bird, plane, insect — can satisfy. An abstract class is a half-built house: it has real walls and a foundation (shared state) but leaves the roof for you to finish, and you can only inherit from one such house.

saying these in an interview costs you the question

  • Saying 'a class can extend multiple abstract classes' — Java allows only single class inheritance.
  • Claiming interfaces can hold instance fields/state — interface fields are implicitly public static final constants only.
  • Saying interfaces have no method bodies at all — since Java 8 they have default and static methods (and private helpers since Java 9).
  • Asserting abstract classes can't have constructors — they can and do, invoked via super() from subclasses.
  • Treating the choice as purely about 'how many methods have bodies' rather than state, type-multiplicity, and is-a vs capability.

context