Создание многоуровневой иерархии

До сих пор мы использовали простые иерархии классов, которые состояли только из суперкласса и подкласса. Однако можно строить иерархии, которые содержат любое количество уровней наследования. Как уже отмечалось, вполне допустимо использовать подкласс в качестве суперкласса другого подкласса. Например, класс С может быть подклассом класса В, который, в свою очередь, является подклассом класса А. В подобных ситуациях каждый подкласс наследует все характеристики всех его суперклассов. В приведенном примере класс с наследует все характеристики классов в и А. В качестве примера многоуровневой иерархии рассмотрим следующую программу. В ней подкласс BoxWeight использован в качестве суперкласса для создания подкласса Shipment. Shipment наследует все характеристики классов BoxWeight и Box и добавляет поле cost, которое содержит стоимость поставки такого пакета.

// Расширение класса BoxWeight за счет включения в него стоимости доставки.
// Начнем с создания класса Box.
class Box {
private double width;
private double height;
private double depth; // конструирование клона объекта
Box(Box ob) {
// передача объекта конструктору
width = ob.width;
height = ob.height;
depth = ob.depth;
}
// конструктор, используемый при указании всех измерений
Box(double w, double h, double d) {
width = w;
height = h;
depth = d;
}
// конструктор, используемый, когда ни одно из измерений не указано
Box () {
width = -1; // значение -1 используется для указания
height = -1; // неинициализированного
depth = -1; // параллелепипеда
}
// конструктор, используемый при создании куба
Box(double len) {
width = height = depth = len;
}
// вычисление и возврат объема
double volume() {
return width * height * depth;
}
}
// Добавление веса.
class BoxWeight extends Box {
double weight; // вес параллелепипеда
// конструирование клона объекта
BoxWeight(BoxWeight ob) {
// передача объекта конструктору super(ob) ;
weight = ob.weight;
// конструктор, используемый при указании всех параметров
BoxWeight(double w, double h, double d, double m) {
super(w, h, d) ; // вызов конструктора суперкласса
weight = m;
}
// конструктор, используемый по умолчанию BoxWeight () {
super();
weight = -1;
}
// конструктор, используемый при создании куба
BoxWeight(double len, double m) {
super(len);
weight = m;
// Добавление стоимости доставки.
class Shipment extends BoxWeight {
double cost; // конструирование клона объекта
Shipment(Shipment ob) {
// передача объекта конструктору
super(ob);
cost = ob.cost;
}
// конструктор, используемый при указании всех параметров
Shipment(double w, double h, double d, double m, double c) {
super(w, h, d, m) ; // вызов конструктора суперкласса
cost = с;
}
// конструктор, используемый по умолчанию
Shipment () {
super ();
cost = -1 ;
}
// конструктор, используемый при создании куба
Shipment(double len, double m, double c) {
super(len, m);
cost = c;
}
}
class DemoShipment {
public static void main(String args[]) {
Shipment shipmentl = new Shipment (10, 20, 15, 10, 3.41);
Shipment shipment2 = new Shipment(2, 3, 4, 0.76, 1.28);
double vol;
vol = shipmentl.volume();
System.out.println("Объем shipmentl равен " + vol);
System.out.println("Bee shipmentl равен " + shipmentl.weight) ,
System.out.println("Стоимость доставки: $" + shipmentl.cost) System.out.println ();
vol = shipment2.volume();
System.out.println("Объем shipment2 равен " + vol);
System.out.println ("Bee shipment2 равен " + shipment2.weight);
System.out.println("Стоимость доставки: $" + shipment2.cost)
}
}

Эта программа создает следующий вывод:

Объем shipmentl равен 3000.0
Вес shipmentl равен 10.0
Стоимость доставки: $3.41
Объем shipment2 равен 24.0
Вес shipment2 равен 0.76
Стоимость доставки: $1.28

Благодаря наследованию, класс Shipment может-использовать ранее определенные классы Box и BoxWeight, добавляя только ту дополнительную информацию, которая требуется для его собственного специализированного применения. В этом состоит одно из ценных свойств наследования. Оно позволяет повторно использовать код.

Приведенный пример иллюстрирует важный аспект: конструктор super () всегда ссылается на конструктор ближайшего в суперкласса в иерархии. Конструктор super () в классе Shipment вызывает конструктор класса BoxWeight. Конструктор super () в классе BoxWeight вызывает конструктор класса Box. Если в иерархии классов конструктор суперкласса требует передачи ему параметров, все подклассы должны передавать эти параметры "по эстафете". Данное утверждение справедливо независимо от того, нуждается ли подкласс в собственных параметрах.

На заметку! В приведенном примере программы вся иерархия классов, включая Box, BoxWeight и Shipment, находится в одном файле. Это сделано только ради удобства. В Java все три класса могли бы быть помещены в отдельные файлы и компилироваться независимо друг от друга. Фактически, использование отдельных файлов — норма, а не исключение при создании иерархий классов.