In the last lesson a child class added new fields and methods. Often a child needs something different: it should do the same job as the parent, but in its own way. Apex lets a child replace a parent method, as long as the parent agrees to it.
A parent method can only be replaced if it is marked virtual. The child then writes a method with the same name, parameters, and return type, marked override:
public virtual class Greeter {
public virtual String greet(String name) {
return 'Hello, ' + name;
}
}
public class PirateGreeter extends Greeter {
public override String greet(String name) {
return 'Ahoy, ' + name;
}
}
Both keywords are required. Without virtual on the parent method, the override is a compile error. Without override on the child method, Apex also refuses to compile, so you can never replace a method by accident.
An override does not have to start from scratch. super.methodName(...) calls the parent version, so the child can build on it:
public class LoudGreeter extends Greeter {
public override String greet(String name) {
return super.greet(name) + '!!!';
}
}
new LoudGreeter().greet('Sam') returns Hello, Sam!!!. If the parent ever changes its greeting, the child picks up the change for free.
This is the powerful part. When a variable has the parent type but holds a child object, Apex runs the version that belongs to the actual object:
List<Greeter> greeters = new List<Greeter>{ new Greeter(), new PirateGreeter() };
for (Greeter g : greeters) {
System.debug(g.greet('Sam'));
}
// Hello, Sam
// Ahoy, Sam
The loop never checks which kind of greeter it has. This idea is called polymorphism: one call, many behaviors.
In the exercise editor you leave virtual off the class itself, because every class there can already be extended, and writing it is a compile error. Methods are different: a method still needs virtual before a child can override it, and the child still needs override, exactly like in a real org.
Polymorphism lets you add new behavior without editing the code that uses it. A discount engine can loop over a list of rules and call apply() on each one. Adding a new kind of rule means writing one new child class, not touching the loop.