Inheritance, Polymorphism, and Interfaces
Class: CSCE-314
Notes:
Up to now, we’ve looked at classes, objects, and encapsulation. Each class has represented a single concept — like a Student, a BankAccount, or a Car. But what happens when we notice patterns across classes? Many share behavior or data, and rewriting the same code violates our DRY (Don’t Repeat Yourself) principle.
That’s where inheritance, polymorphism, and interfaces come in. Together, they let us design families of related classes that share code, yet can specialize and behave differently when needed.
1. Inheritance: Building on Existing Classes
Inheritance lets one class (the subclass) reuse and extend another class (the superclass).
// Base class (superclass)
public class Vehicle {
protected String brand;
protected int year;
public Vehicle(String brand, int year) {
this.brand = brand;
this.year = year;
}
public void startEngine() {
System.out.println("The vehicle's engine starts...");
}
}
// Derived class (subclass)
public class Car extends Vehicle {
private int doors;
public Car(String brand, int year, int doors) {
super(brand, year); // Call superclass constructor
this.doors = doors;
}
@Override
public void startEngine() {
System.out.println("The car engine roars to life!");
}
public void honk() {
System.out.println("Beep! Beep!");
}
}
Vehicle v1 = new Vehicle("Generic", 2010);
Car c1 = new Car("Toyota", 2021, 4);
v1.startEngine(); // The vehicle's engine starts...
c1.startEngine(); // The car engine roars to life!
- Note
super(brand, year)- Super is the
Vehicleclass - It does not necessarily knows anything about the doors
- Super is the
- Now the
@OverrideinCarwill replace thestartEngine()function withinVehicleto be the one defined withinCar.
2. Polymorphism: Many Forms of Behavior
Polymorphism literally means “many forms.” When we use a superclass reference to refer to a subclass object, we can call the methods defined in the superclass — and if they’re overridden, the subclass’s version runs instead.
Vehicle myVehicle = new Car("Honda", 2022, 4);
myVehicle.startEngine(); // The car engine roars to life!
Vehicle[] garage = {
new Car("Toyota", 2021, 4),
new Truck("Ford", 2018, 2),
new Motorcycle("Yamaha", 2022)
};
for (Vehicle v : garage) {
v.startEngine(); // Calls each subclass’s version
}
- You can create an array of all of those items!
- The
forloop here is an enhanced for loop.
3. Abstract Classes: Defining a Template for Subclasses
public abstract class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public abstract void makeSound(); // Must be implemented by subclasses
}
public class Dog extends Animal {
public Dog(String name) { super(name); }
@Override
public void makeSound() {
System.out.println(name + " says: Woof!");
}
}
- An
abstractclass is a restricted class that cannot be instantiated directly. This means you cannot create objects of an abstract class usingnew AbstractClassName() - To use an abstract class, it must be inherited by another class (a subclass).
- The implementation of an abstract method must be provided by the concrete subclass that inherits the abstract class. This forces subclasses to provide their own specific implementations for certain behaviors.
- Abstract classes can contain both abstract methods and concrete (regular) methods.
- An
abstractmethod is a method declared without an implementation (without a method body, only a semicolon after the signature).
- An
- If a class contains at least one
abstractmethod, the class itself must be declaredabstract.- Abstract methods can only be declared within an
abstractclass.
- Abstract methods can only be declared within an
4. Interfaces: Defining Behavior without Implementation
Interface: a class that says "I do not care how you implement this set of functions just that you have to have them in order to use my interface"
- Implementation specific for whoever uses that interface
public interface Drivable {
void accelerate();
void brake();
}
public class Bicycle implements Drivable {
public void accelerate() {
System.out.println("Pedaling faster!");
}
public void brake() {
System.out.println("Applying the hand brakes!");
}
}
List<Drivable> thingsToDrive = List.of(new Bicycle(), new Car("Tesla", 2023, 4));
for (Drivable d : thingsToDrive) {
d.accelerate();
}
- Note the
implementskeyword, this is how we define interfaces. - Now
Bicyclerequires those two functions.
5. Design Considerations and Best Practices
- Favor composition over inheritance — Sometimes a class should use another rather than extend it.
- Use inheritance for “is-a” relationships — A Car is a Vehicle, but a Garage is not a Vehicle.
- Mark overridden methods with
@Override— This catches mistakes at compile time. - Keep superclass fields
protectedorprivate— Maintain encapsulation and provide access through methods. - Interfaces define roles — A class can “play” multiple roles by implementing multiple interfaces.
- Abstract classes define common state and partial behavior — Use them when you need both shared code and required methods.
6. Mini Example: Animals and Interfaces
public interface Pet {
void beFriendly();
}
public abstract class Animal {
public abstract void makeSound();
}
public class Dog extends Animal implements Pet {
@Override
public void makeSound() { System.out.println("Woof!"); }
public void beFriendly() { System.out.println("Wags tail."); }
}
public class Cat extends Animal implements Pet {
@Override
public void makeSound() { System.out.println("Meow!"); }
public void beFriendly() { System.out.println("Purrs softly."); }
}
List<Pet> pets = List.of(new Dog(), new Cat());
for (Pet p : pets) {
p.beFriendly();
}
- All the code that is in
Animalis inPetand a little bit more.
Summary
By the end of this week, you should be able to:
- Explain the difference between inheritance, polymorphism, abstract classes, and interfaces.
- Identify when to use extends vs. implements.
- Implement a class hierarchy that leverages method overriding.
- Design flexible programs using shared interfaces and dynamic dispatch.
Further Reading in Java Java Java: Object-Oriented Problem Solving (4th Edition)
You can explore these chapters and sections in the Open Textbook Library edition:
https://open.umn.edu/opentextbooks/textbooks/java-java-java-object-oriented-problem-solving
- Chapter 9 – Inheritance and Polymorphism
- Chapter 10 – Abstract Classes and Interfaces
- Chapter 11 – Polymorphism and Dynamic Binding
- Figuring out what to do at runtime (while we are running the code) not during compile time.
- Appendix A – Java Language Summary (optional reference for syntax reminders)