Skip to main content

Section 9.4 Choosing Between Abstract Classes and Interfaces

The choice between abstract classes and interfaces can sometimes confuse beginners. Here’s a practical comparison:

Note 9.4.1. Understanding "Contracts" in Java.

Both abstract classes and interfaces define "contracts" but in different ways:
  • Abstract classes represent a partial implementation contract: "Here’s some common state and behavior, but you must implement these specific methods."
  • Interfaces represent a pure responsibility contract: "Any class implementing this must provide these capabilities, regardless of its inheritance hierarchy."
Abstract classes focus on what a class is (identity), while interfaces focus on what a class can do (capability).
Feature Abstract Classes Interfaces
Fields Can have instance fields Only constants (static final)
Methods Mix of abstract and concrete Abstract (+ default since Java 8)
Implementation Can provide partial implementation Only through default methods
Constructors Yes No
Multiple inheritance No (only one superclass) Yes (implement multiple)
Access modifiers Any (public, protected, private) Only public
Based on the comparison, here are guidelines for choosing:
  • Use Abstract Classes when:
    • You have shared state (fields) that subclasses need
    • You want to provide some common method implementations
    • You have a clear "is-a" relationship in your domain
    • You need to use non-public members (protected methods, fields)
  • Use Interfaces when:
    • You want classes to fulfill multiple roles or behaviors independently
    • You have unrelated classes that share common method signatures but no shared state
    • You want maximum flexibility for future classes
    • You’re defining a capability rather than a type of object
Concrete Example Contrast:
Abstract Class Example
A Vehicle abstract class makes sense because:
  • All vehicles share common state (model, speed, position)
  • There’s clearly an "is-a" relationship (Car is a Vehicle)
  • Common behaviors can be implemented once (accelerate, decelerate)
  • Some methods need customization in subclasses (start, stop)
Interface Example
A Printable interface makes sense because:
  • Many unrelated classes (Document, Invoice, User) might need printing capability
  • These classes don’t share a common superclass
  • No shared state is needed for printing
  • The capability can be added independently of inheritance hierarchy
Let’s look at some examples from different domains:
Document Processing System
Abstract class: Document with fields for common properties and some shared implementation
Interfaces: Printable, Searchable, Editable as capabilities
Class hierarchy:
Document (abstract class with common behavior)
PDFDocument extends Document, implements Printable, Searchable
WordDocument extends Document, implements Printable, Searchable, Editable
ImageDocument extends Document, implements Printable
Vehicle System Example
Abstract class: Vehicle with model, position, and shared behaviors
Interfaces: Drivable, Electric, Towable as capabilities
Class hierarchy:
Vehicle (abstract class with common behavior)
Car extends Vehicle, implements Drivable
ElectricCar extends Vehicle, implements Drivable, Electric
Trailer extends Vehicle, implements Towable
Real-world systems often combine both approaches to create flexible and organized designs.

Insight 9.4.2. Hybrid Design: Combining Abstract Classes and Interfaces.

In complex applications, you’ll often use both abstract classes and interfaces together. Let’s build this up step by step using our vehicle example:
Step 1: First, we define our abstract class for common vehicle behavior and state:
// Abstract base class - handles common state and partial implementation
public abstract class Vehicle {
    protected String model;
    protected double position;
    
    // Common implementation shared by all vehicles
    public String getModel() {
        return model;
    }
    
    // Abstract methods that all vehicles must implement
    public abstract void start();
    public abstract void stop();
}
Step 2: Next, we define interfaces for optional capabilities vehicles might have:
// Interface for vehicles that are electric powered
public interface Electric {
    void charge();
    int getBatteryLevel();
}

// Interface for vehicles that can tow other vehicles
public interface Towable {
    void tow(Vehicle other);
    int getTowingCapacity();
}
Step 3: Finally, we create concrete vehicle types that combine the abstract class with selected interfaces:
// Concrete class using both approaches
public class ElectricTruck extends Vehicle 
        implements Electric, Towable {
    
    private int batteryLevel;
    private int towingCapacity;
    
    // Implement required abstract methods from Vehicle
    @Override
    public void start() { 
        if (batteryLevel > 10) {
            System.out.println("Starting electric motor...");
        } else {
            System.out.println("Battery too low to start!");
        }
    }
    
    @Override
    public void stop() { 
        System.out.println("Stopping electric motor...");
    }
    
    // Implement Electric interface
    @Override
    public void charge() { 
        batteryLevel = 100;
        System.out.println("Battery fully charged");
    }
    
    @Override
    public int getBatteryLevel() {
        return batteryLevel;
    }
    
    // Implement Towable interface
    @Override
    public void tow(Vehicle other) {
        System.out.println("Towing " + other.getModel());
    }
    
    @Override
    public int getTowingCapacity() {
        return towingCapacity;
    }
}
This design leverages the strengths of both approaches:
  • The abstract class (Vehicle) provides shared state (fields) and some implementation
  • The interfaces add optional capabilities (Electric, Towable)
  • Different vehicle types can mix and match these capabilities as needed
Key takeaways for choosing between abstract classes and interfaces:
  • Use abstract classes for "is-a" relationships with shared state and implementation
  • Use interfaces for "can-do" capabilities that may apply to diverse classes
  • Consider using both in combination for complex systems
  • Remember: Java allows single inheritance but multiple interface implementation
  • Avoid deep inheritance hierarchies (more than 2-3 levels) to reduce complexity. Deep hierarchies can lead to:
    • Fragile code that breaks when superclasses change
    • Difficulty understanding the full behavior of a class
    • "Method origin confusion" (which superclass does this method come from?)
    • Reduced maintainability and code flexibility

Exercises Exercises

1.

For the following scenario, decide whether an abstract class or an interface would be the better design choice:
A set of shapes in a drawing application where every shape must have an area and perimeter calculation, but some shapes might require different additional properties (e.g., a circle has a radius, a rectangle has width and height).
  • Abstract class
  • Interface

2.

For the following scenario, decide whether an abstract class or an interface would be the better design choice:
A set of devices (e.g., printers, scanners, projectors) that must implement a connect() method but may have completely different ways of working otherwise.
  • Abstract class
  • Interface

3.

For the following scenario, decide whether an abstract class or an interface would be the better design choice:
A hierarchy of vehicles where all vehicles share common attributes like speed and fuel capacity, but different types of vehicles (cars, boats, planes) have specialized behaviors.
  • Abstract class
  • Interface

4.

For the following scenario, decide whether an abstract class or an interface would be the better design choice:
A payment system where different payment methods (credit card, PayPal, bank transfer) must implement a processPayment() method but don’t share any default implementation.
  • Abstract class
  • Interface

5.

For the following scenario, decide whether an abstract class or an interface would be the better design choice:
A game where different types of characters (warrior, mage, archer) have common characteristics such as health and attack power, but specific attack strategies differ.
  • Abstract class
  • Interface

6.

    True or False: An interface can have constructors.
  • True.

  • Interfaces cannot have constructors. Constructors are used to initialize object state, but interfaces cannot contain instance variables (except constants).
  • False.

  • Interfaces cannot have constructors. Constructors are used to initialize object state, but interfaces cannot contain instance variables (except constants).

7.

    True or False: Abstract classes can contain only abstract methods.
  • True.

  • Abstract classes can contain a mix of abstract methods AND concrete methods with implementations. In fact, this is one of their key advantages over interfaces.
  • False.

  • Abstract classes can contain a mix of abstract methods AND concrete methods with implementations. In fact, this is one of their key advantages over interfaces.

8.

    True or False: A class can implement multiple interfaces at the same time.
  • True.

  • This is correct. Java allows a class to implement multiple interfaces simultaneously, which is a way to achieve a form of multiple inheritance for behavior.
  • False.

  • This is correct. Java allows a class to implement multiple interfaces simultaneously, which is a way to achieve a form of multiple inheritance for behavior.

9.

    True or False: You can create an instance of an abstract class directly.
  • True.

  • You cannot instantiate abstract classes directly. You must create a concrete subclass that implements all abstract methods, then instantiate that subclass.
  • False.

  • You cannot instantiate abstract classes directly. You must create a concrete subclass that implements all abstract methods, then instantiate that subclass.

10.

    True or False: Interface methods are implicitly public and abstract.
  • True.

  • This is correct. In interfaces, methods are implicitly public and abstract (except for default methods, which have implementations).
  • False.

  • This is correct. In interfaces, methods are implicitly public and abstract (except for default methods, which have implementations).

11.

What is one advantage of using an abstract class over an interface?
  • An abstract class allows multiple inheritance.
  • Incorrect. Java does not support multiple inheritance for classes, but a class can implement multiple interfaces.
  • An abstract class can provide concrete methods with instance variables.
  • Correct! Abstract classes can define instance fields and provide methods that use them.
  • An abstract class allows multiple class extensions.
  • Incorrect. A class can only extend one abstract class, but it can implement multiple interfaces.
  • An abstract class does not require subclasses to implement all abstract methods.
  • Incorrect. A subclass must implement all abstract methods unless it is itself declared abstract.

12.

What is an advantage of using interfaces over abstract classes?
  • Interfaces allow defining instance variables.
  • Incorrect. Interfaces do not allow instance variables, only constants (public static final).
  • A class can implement multiple interfaces but extend only one abstract class.
  • Correct! This flexibility allows a class to inherit behavior from multiple sources.
  • Interfaces can contain only abstract methods, while abstract classes can have default methods.
  • Incorrect. Interfaces can have default methods, so this statement is outdated.
  • Interfaces require implementing classes to define all methods.
  • Incorrect. Interfaces can have default methods, which do not require implementation.
You have attempted of activities on this page.