Problem overview
A company pays every employee a salary. A manager is an employee too, but earns a bonus on top of the salary. The task is to write two classes so that Manager reuses everything Employee has and changes only how the pay is worked out.
Employee(name, salary)stores the name and the salary, bothprivate.pay()returns the salary.describe()returns text such asAna earns 3000, using the value ofpay().Manager(name, salary, bonus)extendsEmployee, passes the name and salary to the parent, and stores the bonus itself.- A manager's
pay()is the parent'spay()plus the bonus.describe()is not written again.
An employee called Ana with a salary of 3000 earns 3000. A manager called Bob with a salary of 4000 and a bonus of 1000 earns 5000, and his description says so.
Approach: override one method, inherit the rest
Inheritance means a subclass starts with everything its parent has. Manager extends Employee, so a manager already has a name, a salary, pay and describe. The only difference is the pay rule, so Manager overrides pay and nothing else.
The trick is in describe. It calls pay() instead of reading the salary. When describe runs on a manager, the call pay() goes to the manager's version, so the bonus appears in the text without a second describe. Java picks the method by the real type of the object, not by the type of the variable that holds it.
The salary is private to Employee, so Manager can't read it. That is why Manager.pay calls super.pay(): the parent's version knows how an employee is paid.
Step by step
- Declare
private String nameandprivate int salaryinEmployee. Private means not evenManagercan use them directly. - The constructor stores both with
this.name = nameandthis.salary = salary. payreturnssalary.describereturnsname + " earns " + pay(). Adding anintto aStringwith+turns the number into text. Callingpay()rather than readingsalaryis what makes managers work.- Write
Manager extends Employeewith its ownprivate int bonus. - Start the constructor with
super(name, salary). It runsEmployee's constructor, the only code that can fill in the private fields. Java requires it to be the first line. - Store the bonus with
this.bonus = bonus. - Override
pay: returnsuper.pay() + bonus.
The solution in Java
class Employee {
private String name;
private int salary;
public Employee(String name, int salary) {
this.name = name;
this.salary = salary;
}
public int pay() {
return salary;
}
public String describe() {
return name + " earns " + pay();
}
}
class Manager extends Employee {
private int bonus;
public Manager(String name, int salary, int bonus) {
super(name, salary);
this.bonus = bonus;
}
@Override
public int pay() {
return super.pay() + bonus;
}
}
Java details:
@Overrideasks the compiler to check that the method really overrides one from the parent. A typo such asPaywould then be an error instead of a silent new method.super.pay()calls the parent's version. Writing justpay()insideManager.paywould call the same method again, forever. The program would end with aStackOverflowError.- If
Manager's constructor didn't callsuper(...), Java would look for anEmployeeconstructor with no parameters. There is none, so it wouldn't compile.
The classes divide the work cleanly. Employee knows how to store a person and how to write the sentence. Manager knows only what makes a manager different: one extra number and one changed rule. Anything else about managers, such as the name and the sentence, comes from the parent.
Using the classes
Employee[] staff = {
new Employee("Ana", 3000),
new Manager("Bob", 4000, 1000),
new Manager("Cleo", 5000, 0),
new Manager("Eve", 7000, 2500),
new Employee("Finn", 2800)
};
for (Employee e : staff) {
System.out.println(e.describe());
}
prints:
Ana earns 3000
Bob earns 5000
Cleo earns 5000
Eve earns 9500
Finn earns 2800
The array holds both kinds of object as Employee, and each call to describe() still uses the right pay(). A manager with a bonus of 0, such as Cleo, earns exactly her salary.
How one describe call is worked out
For Bob, created as new Manager("Bob", 4000, 1000), the call describe() goes through these steps:
Managerhas nodescribe, so Java uses the one it inherited fromEmployee.- That method builds
name + " earns " + pay(). The object is aManager, sopay()runsManager's version. - That version calls
super.pay(), which isEmployee's version and returns the salary, 4000, and then adds the bonus, 1000. - The text becomes
Bob earns 5000.
In the array above, the variable e has the type Employee for every element, yet the call that runs depends on the object that e refers to at that moment. This is called polymorphism, and it is why describe needs no changes for new kinds of employees: a class that overrides pay gets a correct description for free.
Common mistakes
- Reading
salaryindescribe. Managers would show their salary without the bonus. - Writing
describeagain inManager. It works, but it copies code, and the point of inheritance is to avoid that. - Calling
pay()instead ofsuper.pay()inside the override. The method calls itself and never returns. - Making the fields
publicto avoidsuper. It compiles, but it gives up the protectionprivateprovides. - Not passing every parent argument to
super. The name and the salary both go there; only the bonus is stored inManager.
Complexity
Each method runs in O(1) time, apart from building the text in describe, which is proportional to the length of the name, at most 20 letters here. Each object stores a name and one or two integers.
