Эккель Брюс
Шрифт:
Как видите, конструирование начинается с «самого внутреннего» базового класса, поэтому базовый класс инициализируется еще до того, как он станет доступным для конструктора производного класса. Даже если конструктор класса Cartoon не определен, компилятор сгенерирует конструктор по умолчанию, в котором также вызывается конструктор базового класса.
Конструкторы с аргументами
В предыдущем примере использовались конструкторы по умолчанию, то есть конструкторы без аргументов. У компилятора не возникает проблем с вызовом таких конструкторов, так как вопросов о передаче аргументов не возникает. Если класс не имеет конструктора по умолчанию или вам понадобится вызвать конструктор базового класса с аргументами, этот вызов придется оформить явно, с указанием ключевого слова super и передачей аргументов:
//: reusing/Chess.java
// Наследование, конструкторы и аргументы.
import static net.mindview.util.Print.*;
class Game {
Game(int i) {
print("Конструктор Game"),
}
}
class BoardGame extends Game { BoardGame(int i) { super(i);
print("Конструктор BoardGame");
}
}
public class Chess extends BoardGame { Chess О {
super(ll);
print("Конструктор Chess");
}
public static void main(String[] args) { Chess x = new ChessO:
}
} /* Output-Конструктор Game Конструктор BoardGame Конструктор Chess *///:-
Если не вызвать конструктор базового класса в BoardGame, то компилятор «пожалуется» на то, что не может обнаружить конструктор в форме Game. Вдобавок вызов конструктора базового класса должен быть первой командой в конструкторе производного класса. (Если вы вдруг забудете об этом, компилятор вам тут же напомнит.)
Делегирование
Третий вид отношений, не поддерживаемый в Java напрямую, называется делегированием. Он занимает промежуточное положение между наследованием и композицией: экземпляр существующего класса включается в создаваемый класс (как при композиции), но в то же время все методы встроенного объекта становятся доступными в новом классе (как при наследовании). Например, класс SpaceShipControls имитирует модуль управления космическим кораблем:
//. reusing/SpaceShipControls.java
public class SpaceShipControls { void up(int velocity) {} void down(int velocity) {} void left(int velocity) {} void right(int velocity) {} void forward(int velocity) {} void back(int velocity) {} void turboBoostO {} } ///-
Для построения космического корабля можно воспользоваться наследованием:
// reusing/SpaceShip java
public class SpaceShip extends S^ceShipControls { private String name.
public SpaceShip(String name) { this.name = name, }
public String toStringO { return name. }__
public static void main(String[] args) {
SpaceShip protector = new SpaceShipC'NSEA Protector"), protector forward(lOO).
}
} /// ~
Однако космический корабль не может рассматриваться как частный случай своего управляющего модуля — несмотря на то, что ему, к примеру, можно приказать двигаться вперед (forward). Точнее сказать, что SpaceShip содержит SpaceShipControls, и в то же время все методы последнего предоставляются классом SpaceShip. Проблема решается при помощи делегирования:
// reusing/SpaceShipDelegation java
public class SpaceShipDelegation { private String name, private SpaceShipControls controls =
new SpaceShipControlsO: public SpaceShipDelegation(String name) {
this name = name. }
// Делегированные методы: public void back(int velocity) { controls.back(velocity);
}
public void down(int velocity) { controls.down(velocity);
}
public void forward(int velocity) { controls forward(velocity).
}
public void leftCint velocity) { controls left(velocity).
}
public void rightOnt velocity) { controls right(velocity);
}
public void turboBoostO {
controls.turboBoostO.
}
public void up(int velocity) { controls.up(velocity):
}
public static void main(String[] args) { SpaceShipDelegation protector =
new SpaceShipDelegationC'NSEA Protector"); продолжение &
protector.forwarcK 100);
}
} ///:-
Как видите, вызовы методов переадресуются встроенному объекту controls, а интерфейс остается таким же, как и при наследовании. С другой стороны, делегирование позволяет лучше управлять происходящим, потому что вы можете ограничиться небольшим подмножеством методов встроенного объекта.
Хотя делегирование не поддерживается языком Java, его поддержка присутствует во многих средах разработки. Например, приведенный пример был автоматически сгенерирован в JetBrains Idea IDE.
Сочетание композиции и наследования
Композиция очень часто используется вместе с наследованием. Следующий пример демонстрирует процесс создания более сложного класса с объединением композиции и наследования, с выполнением необходимой инициализации в конструкторе:
II: reusing/PlaceSetting.java 11 Совмещение композиции и наследования, import static net.mindview.util.Print.*;