Abstract Class vs Interface

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 5 min

TL;DR

  • Abstract Class: Represents an “IS-A” relationship. Can have state (instance variables) and constructors. A class can extend only ONE abstract class.
  • Interface: Represents a “CAN-DO” relationship (a capability). Cannot hold state (only public static final constants). A class can implement MULTIPLE interfaces.

Concept

If you are modeling a Dog, an Abstract Class (Animal) makes sense because a dog is an animal. The abstract class can hold shared state like int age; and a constructor to initialize it. All animals breathe the same way, so you provide a concrete breathe() method, but force subclasses to implement makeSound().

If you also want the Dog to be serializable, you use an Interface (Serializable). An interface defines a contract or a capability. A Dog can be serializable, and a String can be serializable, even though they share no IS-A relationship. Because Java does not support Multiple Inheritance for classes to prevent the “Diamond Problem”, a class can only extend one abstract class, but it can implement 50 interfaces.

Note: Since Java 8, Interfaces can have default methods, blurring the line between the two.

Examples

// 1. ABSTRACT CLASS
// Holds state, constructors, and access modifiers.
abstract class Animal {
    protected int age; // State!
    
    public Animal(int age) { this.age = age; } // Constructor!
    
    public void sleep() { System.out.println("Zzz..."); } // Concrete method
    public abstract void makeSound(); // Forced implementation
}

// 2. INTERFACE
// Only defines capabilities. Cannot hold instance state.
interface Pet {
    // Variables in interfaces are implicitly public static final!
    int MAX_PETS = 5; 
    
    void play(); // implicitly public abstract
    
    // Java 8 default method
    default void eat() { System.out.println("Eating..."); }
}

// A class can extend ONE abstract class, but MULTIPLE interfaces.
class Dog extends Animal implements Pet {
    public Dog(int age) { super(age); }
    
    @Override
    public void makeSound() { System.out.println("Woof"); }
    
    @Override
    public void play() { System.out.println("Catching frisbee"); }
}

Interview Questions

Q: If interfaces can now have default methods (Java 8), why do we still need Abstract Classes?
A: Because interfaces still cannot hold State (instance variables) and they cannot have Constructors.
If all animals share an age variable and need a constructor to initialize that age, you absolutely must use an Abstract Class. Interfaces can only hold static final constants.

Q: What is the “Diamond Problem” and how does Java solve it?
A: If a class was allowed to inherit from two abstract classes (A and B), and both classes implemented a print() method differently, which print() would the child class inherit? This ambiguity is the Diamond Problem.
Java solves this by strictly forbidding multiple inheritance for classes.
However, what if a class implements two interfaces that both provide a default print() method? The Java compiler will instantly throw a compilation error, forcing the developer to explicitly override the print() method in the child class to resolve the ambiguity manually.