1. The Hook (The "Byte-Sized" Intro)
In a Nutshell: Choose abstract classes when you need shared state, constructors, or partial implementation with an "is-a" relationship. Choose interfaces when you need multiple inheritance, pure contracts, or "can-do" capabilities. Java 8+ blurred the lines with default methods, but the core difference remains: abstract classes have state; interfaces define behavior.
Think of Car vs License. A Car (abstract class) has state (fuel, speed) and partial implementation (start engine). A License (interface) is just a contract saying "I can drive"—no state, just capability!
2. Conceptual Clarity (The "Simple" Tier)
💡 The Analogy
- Abstract Class: A partially built house (foundation + some walls done, you finish the rest)
- Interface: An architect's blueprint (just the plan, no construction)
3. Technical Mastery (The "Deep Dive")
Key Differences Table
| Feature | Abstract Class | Interface |
|---|---|---|
| Multiple Inheritance | ❌ No (single parent) | ✅ Yes (multiple interfaces) |
| Fields | Any fields allowed | Only public static final constants |
| Constructors | ✅ Yes | ❌ No |
| Methods | Abstract + Concrete | Abstract + Default (Java 8+) + Static |
| Access Modifiers | Any (private, protected, etc.) | public only (for methods) |
| Relationship | "is-a" | "can-do" (capability) |
| When to Use | Shared state/behavior | Pure contract/multiple inheritance |
The "Why" Paragraph
Before Java 8, the choice was clear: interfaces for contracts, abstract classes for partial implementation. Java 8's default methods made interfaces more powerful, but abstract classes still win when you need state (instance variables) or constructors. Use abstract classes for true hierarchies (Vehicle → Car → ElectricCar) and interfaces for capabilities (Flyable, Rechargeable).
4. Interactive & Applied Code
// ABSTRACT CLASS: Shared state + partial implementation
abstract class Vehicle {
String brand; // State!
int speed = 0;
Vehicle(String brand) { // Constructor!
this.brand = brand;
}
void start() { // Concrete method
System.out.println(brand + " starting...");
}
abstract void accelerate(); // Abstract method
}
class Car extends Vehicle {
Car(String brand) {
super(brand);
}
@Override
void accelerate() {
speed += 10;
System.out.println("Car accelerating: " + speed);
}
}
// INTERFACE: Pure contract (capability)
interface Flyable {
void fly(); // No state, no constructor
}
interface Rechargeable {
void charge();
int getBatteryLevel();
}
// Combining both!
class FlyingCar extends Vehicle implements Flyable, Rechargeable {
int batteryLevel = 100;
FlyingCar(String brand) {
super(brand);
}
@Override
void accelerate() {
speed += 20;
System.out.println("Flying car accelerating: " + speed);
}
@Override
public void fly() {
System.out.println("Flying car taking off!");
}
@Override
public void charge() {
batteryLevel = 100;
}
@Override
public int getBatteryLevel() {
return batteryLevel;
}
}5. Decision Tree
6. The "Interview Corner" (The Edge)
The "Killer" Interview Question: "With Java 8 default methods, why use abstract classes?" Answer:
- State: Abstract classes can have instance variables; interfaces cannot
- Constructors: Abstract classes have constructors for initialization
- Access control: Abstract classes can have
private/protectedmembers - Design intent: "is-a" (abstract class) vs "can-do" (interface)
Pro-Tip: Combine both!
abstract class Animal { // Common state
String name;
}
interface Swimmable { } // Capabilities
interface Flyable { }
class Duck extends Animal implements Swimmable, Flyable {
// Best of both worlds!
}