Abstract Classes vs Interfaces
Part of the Object Oriented Programming section of Coddy's Java journey — lesson 38 of 87.
Now that you understand both abstract classes and interfaces, a common question arises: when should you use one over the other? The choice depends on what you're trying to model.
Use an abstract class when classes share a common base with shared state or behavior. Abstract classes can have instance variables, constructors, and a mix of abstract and concrete methods:
public abstract class Animal {
protected String name; // shared state
public Animal(String name) {
this.name = name;
}
public void sleep() { // shared behavior
System.out.println(name + " is sleeping");
}
public abstract void makeSound(); // must be implemented
}Use an interface when you want to define a capability that unrelated classes can share. Interfaces focus on what an object can do, not what it is:
public interface Flyable {
void fly();
}
// Unrelated classes can share this capability
class Bird extends Animal implements Flyable { ... }
class Airplane implements Flyable { ... }
class Drone implements Flyable { ... }Here's a quick comparison:
| Feature | Abstract Class | Interface |
|---|---|---|
| Instance variables | Yes | Only constants |
| Constructors | Yes | No |
| Multiple inheritance | No (single extends) | Yes (multiple implements) |
| Access modifiers | Any | Public only (for abstract methods) |
A practical guideline: if you find yourself creating an abstract class with only abstract methods and no state, an interface is likely the better choice.
Challenge
EasyLet's build a vehicle system that demonstrates when to use abstract classes versus interfaces. You'll model vehicles that share common state and behavior through an abstract class, while adding optional capabilities through interfaces.
You'll organize your code across five files:
Vehicle.java: Create an abstract class that serves as the foundation for all vehicles. Every vehicle has abrandfield (String) and ayearfield (int). Include a constructor to initialize both fields, getter methods for each, and an abstract methodstartEngine()that returns a String. Also add a concrete methodgetInfo()that returns:[brand] ([year]). This is a perfect use case for an abstract class—vehicles share state (brand, year) and some behavior (getInfo), but each starts its engine differently.Convertible.java: Define an interface for vehicles that can convert their roof. This capability isn't tied to what a vehicle is—it's something certain vehicles can do. Declare two methods:openRoof()andcloseRoof(), both returning String.Car.java: Create a class that extendsVehicleand implementsConvertible. A Car has an additionalnumDoorsfield (int). Usesuperto initialize the inherited fields. ImplementstartEngine()to return:[brand] car engine started. ImplementopenRoof()to return:[brand] roof openingandcloseRoof()to return:[brand] roof closing.Motorcycle.java: Create a class that extendsVehiclebut does NOT implementConvertible—motorcycles don't have roofs! A Motorcycle has ahasSidecarfield (boolean). ImplementstartEngine()to return:[brand] motorcycle engine roaring.Main.java: Bring everything together to showcase the difference between abstract classes and interfaces. You'll receive four inputs: a car brand, a car year, a motorcycle brand, and a motorcycle year.Create a Car (with 4 doors) and a Motorcycle (without sidecar). First, demonstrate the shared abstract class behavior by printing
getInfo()for both vehicles—they both inherit this from Vehicle. Then print the result ofstartEngine()for each—notice how each vehicle type implements this differently.Finally, demonstrate the interface capability: since only the Car implements
Convertible, call and printopenRoof()followed bycloseRoof()on the car only.
You will receive four inputs: car brand (String), car year (int), motorcycle brand (String), and motorcycle year (int).
Your output should show six lines total. Notice how both vehicles share the abstract class's state and getInfo() method, but only the Car has the convertible capability—this illustrates when to use each approach!
Cheat sheet
Use an abstract class when classes share a common base with shared state or behavior. Abstract classes can have instance variables, constructors, and a mix of abstract and concrete methods:
public abstract class Animal {
protected String name; // shared state
public Animal(String name) {
this.name = name;
}
public void sleep() { // shared behavior
System.out.println(name + " is sleeping");
}
public abstract void makeSound(); // must be implemented
}Use an interface when you want to define a capability that unrelated classes can share. Interfaces focus on what an object can do, not what it is:
public interface Flyable {
void fly();
}
// Unrelated classes can share this capability
class Bird extends Animal implements Flyable { ... }
class Airplane implements Flyable { ... }
class Drone implements Flyable { ... }| Feature | Abstract Class | Interface |
|---|---|---|
| Instance variables | Yes | Only constants |
| Constructors | Yes | No |
| Multiple inheritance | No (single extends) | Yes (multiple implements) |
| Access modifiers | Any | Public only (for abstract methods) |
Guideline: If you're creating an abstract class with only abstract methods and no state, an interface is likely the better choice.
Try it yourself
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Read inputs
String carBrand = scanner.nextLine();
int carYear = scanner.nextInt();
scanner.nextLine(); // consume newline
String motorcycleBrand = scanner.nextLine();
int motorcycleYear = scanner.nextInt();
// TODO: Create a Car with 4 doors
// TODO: Create a Motorcycle without sidecar (false)
// TODO: Print getInfo() for both vehicles (demonstrates shared abstract class behavior)
// TODO: Print startEngine() for both vehicles (demonstrates different implementations)
// TODO: Print openRoof() and closeRoof() for car only (demonstrates interface capability)
}
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesIntroduction to OOPClasses vs ObjectsThe this KeywordMethodsFields (Attributes)Constructor MethodConstructor OverloadingRecap - Simple Calculator4Inheritance
Basic Inheritance (extends)The super KeywordMethod Overriding (@Override)Constructor ChainingThe Object ClassSingle & Multilevel InheritWhy No Multi Class InheritRecap - Employee Hierarchy7Special Methods & Object Class
toString() Methodequals() and hashCode()clone() MethodcompareTo() and ComparableComparator InterfaceRecap - Custom Sorting2Access Modifiers & Encapsulate
Access Levels OverviewGetter and Setter MethodsInformation HidingThe final KeywordRecap - Bank Account Manager5Polymorphism
Method Overloading BasicsMethod Overriding (Run-Time)Upcasting and DowncastingThe instanceof OperatorAbstract Classes and MethodsRecap - Shape Calculator8Advanced OOP Concepts
Composition vs InheritanceAggregation vs CompositionInner Nested & Anonymous ClassEnums and Enum MethodsRecords (Java 16+)Sealed Classes (Java 17+)3Class Props & Static Member
Instance vs Static VariablesStatic MethodsStatic BlocksConstants (static final)Recap - Counter & Utility6Interfaces & Abstract Classes
Introduction to InterfacesImplementing InterfacesMulti Interface ImplemenDefault & Static in InterfaceAbstract Classes vs InterfacesFunctional InterfacesRecap - Payment System