Существует простое правило, позволяющее определить, стоит ли конкретной ситуации применять наследование или нет. Если между объектами существует отношение «является» («is-a»), то каждый объект подкласса является объектом суперкласса. Например, каждый менеджер является сотрудником. Следовательно, имеет смысл сделать класс Manager подклассом класса Employee. Естественно, обратное утверждение неверно — не каждый сотрудник является менеджером.
Другой способ — принцип подстановки. Этот принцип гласит, что объект подкласса можно использовать вместо любого объекта суперкласса.Например, объект подкласса можно присвоить переменной суперкласса:
1 2 3 |
Employee e; e = new Employee(...); // Объект класса Employee e = new Manager(...); // Можно и так |
В языке Java объектные переменные являются полиморфными. Переменная типа Employee может ссылаться как на объект Employee, так и на объект любого подкласса класса Employee(например, Manager, Executive, Secretary и т.п.).
1 2 3 |
Manager boss = new Manager(...); Employee[] staff = new Employee[3]; staff[0] = boss; |
Здесь переменные staff[0] и boss ссылаются на один и тот же объект. Однако переменная staff[0] рассматривается компилятором только как объект Employee. Это значит, что допускается следующий вызов:
1 |
boss.setBonus(5000); // Ок |
В то же время выражение, приведенное ниже, некорректное:
1 |
staff[0].setBonus(5000); // Ошибка |
Дело в том, что переменная staff[0] объявлена как объект Employee, а метода setBonus() в этом классе нет. Однако присвоить ссылку на объект суперкласса переменной подкласса невозможно. Например, следующий оператор является недопустимым:
1 |
Manager m = staff[i]; // Ошибка |
Причина очевидна: не все сотрудники являются менеджерами. Если бы это присваивание оказалось выполненным, и переменная м могла бы ссылаться на объект Employee, который менеджером не является, то впоследствии оказался бы возможным вызов метода m.setBonus(…), что привело бы к ошибке при выполнении программы.