Intermediate 30 min read

Polymorphism

By the end of this lesson, you'll be able to:

  • Explain polymorphism as treating different types uniformly through a shared type
  • Loop over a collection of a parent/interface type containing several subclasses
  • Recognize why polymorphism reduces the need for type-checking branches

Prerequisites: "Interfaces"

One list, several actual types

List<Shape> shapes = new List<Shape>{
    new Circle(),
    new Rectangle()
};

for (Shape shape : shapes) {
    System.debug(shape.calculateArea());
}
  1. List<Shape> shapes = new List<Shape>{ — typed as List<Shape>, but about to hold a mix of actual types.
  2. new Circle(), — a Circle object.
  3. new Rectangle() — a Rectangle object.
  4. }; — closes the list literal.
  5. (blank line)
  6. for (Shape shape : shapes) { — loops treating every element as a Shape, regardless of its real type.
  7. System.debug(shape.calculateArea()); — calls calculateArea() without ever checking which one it is — each object runs its own overridden version automatically.
  8. } — closes the loop.

This is polymorphism: "many forms" behind one shared type.

What this replaces: manual type-checking

// The version WITHOUT polymorphism — fragile and grows worse over time
for (Object shapeObj : untyped) {
    if (shapeObj instanceof Circle) {
        Circle c = (Circle) shapeObj;
        System.debug(Math.PI * c.radius * c.radius);
    } else if (shapeObj instanceof Rectangle) {
        Rectangle r = (Rectangle) shapeObj;
        System.debug(r.width * r.height);
    }
    // every new shape type means editing this method again
}
  1. // The version WITHOUT polymorphism... — a warning label for what follows.
  2. for (Object shapeObj : untyped) { — loops over untyped objects, so each one's real type must be checked manually.
  3. if (shapeObj instanceof Circle) { — instanceof checks the object's actual runtime type.
  4. Circle c = (Circle) shapeObj; — casts it to Circle before its fields can be used.
  5. System.debug(Math.PI * c.radius * c.radius); — repeats Circle's formula inline, right here in the loop.
  6. } else if (shapeObj instanceof Rectangle) { — checks for the other known type.
  7. Rectangle r = (Rectangle) shapeObj; — casts it to Rectangle.
  8. System.debug(r.width * r.height); — repeats Rectangle's formula inline too.
  9. } — closes the if/else if chain.
  10. // every new shape type means editing this method again — every new shape type means coming back to add another else if branch here.
  11. } — closes the loop.

With polymorphism, adding a new Shape subclass requires zero changes to a loop like the one above — it already knows how to call calculateArea() on anything that's a Shape.

A real business example: Payroll

List<Payable> payees = new List<Payable>{
    new Contractor(),
    new SalariedEmployee()
};

Decimal totalPayout = 0;
for (Payable payee : payees) {
    totalPayout += payee.calculatePayment();
}
  1. List<Payable> payees = new List<Payable>{ — a list of the shared interface type.
  2. new Contractor(), — one kind of payee.
  3. new SalariedEmployee() — a completely different kind of payee.
  4. }; — closes the list literal.
  5. (blank line)
  6. Decimal totalPayout = 0; — running total, starting at zero.
  7. for (Payable payee : payees) { — loops treating every element as Payable.
  8. totalPayout += payee.calculatePayment(); — doesn't need to know or care whether it's paying a contractor or a salaried employee — both fulfil Payable.
  9. } — closes the loop.

One loop handles the entire payroll regardless of how many different payee types exist.

Exercise

Given the Payable interface and Contractor class from the previous lesson, plus a second class SalariedEmployee implementing Payable (returning a fixed 8000), write a loop over a List<Payable> containing one of each, debugging each calculatePayment() result.

Show hint

for (Payable p : payees) { System.debug(p.calculatePayment()); }

Salesforce: ○ Not connected Connect
APEX

Execution Results

Run your code to see the result.

Polymorphism Quiz

1. What does polymorphism let you avoid?

Log in to submit the quiz and save your score.

My Notes

Log in to keep private notes on this lesson.

Questions about this lesson

No questions yet — be the first to ask.

Log in to ask a question about this lesson.

Summary

Polymorphism means code can work with several different types uniformly, as long as they share a parent class or interface — without needing to know or check which specific type it's dealing with.