Материал предоставлен https://it.rfei.ru

Наследование

Существует два основных механизма для построения новых классов из существующих: наследование и агрегация.

Имеет смысл наследовать от существующего класса Vehicle (транспортное средство), чтобы описать класс Car (автомобиль), поскольку автомобиль является транспортным средством. Класс Vehicle имеет несколько частей; поэтому имеет смысл определить композитный объект класса Vehicle, состоящий из объектов-компонентов таких классов, как Motor (двигатель), Axle (вал) и GearBox (коробка передач), которые составляют транспортное средство.

Наследование демонстрируется на примере, реализующем стек символов, который может отобразить свои элементы на терминал. Этот новый стек имеет все свойства и поведения класса CharStack, но он также имеет дополнительную способность выводить свои элементы на экран. Задано, что этот распечатываемый стек является стеком символов, поэтому он может быть выведен из класса CharStack. Эти отношения показаны на рис. 1.6.

Класс PrintableCharStack называется подклассом, класс CharStack называется суперклассом. Класс CharStack служит обобщением (generalization) для всех стеков символов, тогда как класс PrintableCharStack является специализацией (specialization) стеков символов, потому что может также отображать на экран свои элементы.

Рис. 1.6. Диаграмма класса, изображающая отношение наследования

В Java в описании нового класса, получаемого на основе существующего класса, требуется применение оператора extends. Подкласс может расширять только один суперкласс. Подкласс наследует члены суперкласса. Следующий фрагмент кода реализует класс PrintableCharStack.

// Имя исходного файла: PrintableCharStack.java
class PrintableCharStack extends CharStack {  // (1)

  // Метод экземпляра
  public void printStackElements() {          // (2)
    // Реализация метода ...
  }

  // Конструктор явно вызывает конструктор суперкласса
  public PrintableCharStack(int capacity) {
    super(capacity); // (3)
  }
}

Класс PrintableCharStack расширяет класс CharStack в строке (1). В реализации метода printStackElements() в классе PrintableCharStack необходимо обратиться к полю stackArray суперкласса CharStack. Но это поле private и поэтому недоступно в подклассе. Подкласс сможет получить доступ к этим полям, если их доступность изменить на protected в классе CharStack.

В примере 1.3 используется версия класса CharStack, которая соответствующим образом была изменена. Реализация метода printStackElements() показана в строке (2). Конструктор класса PrintableCharStack в строке (3) вызывает конструктор суперкласса CharStack для того, чтобы правильно проинициализировать стек.

Пример 1.3. Определение подкласса

// Имя исходного файла: CharStack.java
public class CharStack {

  // Переменные экземпляра теперь доступны подклассам

  protected char[] stackArray;
  protected int topOfStack;

  // Остальные определения оставляем без изменений.

}
// Имя исходного файла: PrintableCharStack.java
class PrintableCharStack extends CharStack {  // (1)

  // Метод экземпляра
  public void printStackElements() {
    // Реализация метода (2)
    for (char c : stackArray)
      System.out.print(c);  // Выводим каждый символ на экран
    System.out.println();
  }

  // Конструктор явно вызывает конструктор суперкласса
  public PrintableCharStack(int capacity) {
    super(capacity); // (3)
  }
}

Объекты класса PrintableCharStack ведут себя так же, как объекты класса CharStack, но они имеют также дополнительную функциональность, определенную в подклассе.

    PrintableCharStack aPrintableCharStack = new PrintableCharStack(3);
    aPrintableCharStack.push('H');
    aPrintableCharStack.push('i');

    aPrintableCharStack.push('!');
    aPrintableCharStack.printStackElements();  // Будет выведено "Нi!"
Терминология для членов классаАгрегация