Difficulty: Intermediate
What is the difference between an abstract class and an interface? When would you use each, especially after Java 8?
This is a perennial favourite because the honest answer changed with Java 8, and interviewers want to see if you have kept up. Let's do it properly.
Start with intent. An interface defines a capability or contract: what something can do, like Comparable, Runnable, or Flyable. Unrelated classes can implement the same interface. An abstract class defines a partial implementation of a family of closely related things: what something is, with some shared state and behaviour, like a Vehicle base class with an id and a common info() method, leaving start() abstract for subclasses.
Now the technical differences. A class can extend only one abstract class but implement many interfaces, which is Java's way of getting multiple inheritance of type. An abstract class can have instance fields, constructors, and any access modifier on members, and it can hold mutable state. An interface cannot have instance state; its fields are implicitly public static final constants, it has no constructors, and its methods are public by default. Abstract classes can mix abstract and concrete methods freely. Since Java 8, interfaces can also have default methods with a body and static methods, and since Java 9 private helper methods. This blurred the old rule that interfaces are purely abstract, so the popular claim "interfaces give 100 percent abstraction" is outdated.
The remaining crucial difference is state. Because an interface cannot hold instance fields, default methods can only be written in terms of the other abstract methods. If you need shared fields or a constructor that enforces initialisation, you need an abstract class.
How to choose. Use an interface when you want to define a role that many unrelated classes can play, when you expect multiple inheritance of type, or when you are designing an API that should be easy to mock in tests. Use an abstract class when subclasses share code and state, when you want to enforce a template through a constructor or template method, or when you need non-public members. Many well-designed libraries do both: an interface for the contract plus an abstract skeleton implementation, such as List and AbstractList in the JDK, so implementors get the boilerplate free.
Compare across languages. C++ has no interface keyword; an abstract class with only pure virtual functions serves as one. Python uses the abc module, and also supports duck typing where no declared interface is needed. In Java, abstract classes also cannot be instantiated, but they can have a main method, and a class with even one abstract method must itself be abstract.
Also mention that interface default methods were added mainly to evolve APIs without breaking existing implementations, for example List.sort and Collection.stream were added this way.
interface Flyable {
void fly();
default void land() { System.out.println("Landing"); }
}
abstract class Vehicle {
protected final String id;
Vehicle(String id) { this.id = id; }
abstract void start();
void info() { System.out.println("Vehicle " + id); }
}
class Drone extends Vehicle implements Flyable {
Drone(String id) { super(id); }
void start() { System.out.println("Drone " + id + " spinning rotors"); }
public void fly() { System.out.println("Drone flying"); }
}
public class AbstractVsInterface {
public static void main(String[] args) {
Drone d = new Drone("D1");
d.info();
d.start();
d.fly();
d.land();
}
}
#include <iostream>
using namespace std;
struct Logger {
virtual void log(const string& m) = 0; // pure virtual
virtual ~Logger() {}
};
struct ConsoleLogger : Logger {
void log(const string& m) override { cout << "LOG: " << m << endl; }
};
int main() {
ConsoleLogger c;
Logger& l = c;
l.log("started");
}
abstract-class, interface, default-methods, multiple-inheritance