55

55


print'CKoHCTpyKTop Spoon");

class Fork extends Utensil { Fork(int i) {

super(i);

System.out.println("Конструктор Fork");

}

class Knife extends Utensil { Knife(int i) {

super(i):

print("Конструктор Knife");

class Custom {

Custom(int i) {

print("Конструктор Custom");

public class'PIaceSetting extends Custom { private Spoon sp; private Fork frk; private Knife kn; private DinnerPlate pl; public PIaceSetting(int i) { super(i + 1); sp = new Spoon(i + 2); frk = new Fork(i + 3); kn = new Knifed + 4); pl = new DinnerPlated + 5); pri nt("Конструктор PlaceSetti ng"):

}

public static void main(String[] args) {

. PlaceSetting x = new PlaceSetting(9);

}

} /* Output: Конструктор Custom Конструктор Utensil Конструктор Spoon Конструктор Utensil Конструктор Fork Конструктор Utensil Конструктор Knife Конструктор Plate Конструктор DinnerPlate конструктор PlaceSetting *///:-

Несмотря на то, что компилятор заставляет вас инициализировать базовые классы и требует, чтобы вы делали это прямо в начале конструктора, он не сле­дит за инициализацией встроенный объектов, поэтому вы должны сами пом­нить об этом.

Обеспечение правильного завершения

В Java отсутствует понятиедеструктораиз С++ — метода, автоматически вы­зываемого при уничтожении объекта. В Java программисты просто «забывают» об объектах, не уничтожая их самостоятельно, так как функции очистки памяти возложены на сборщика мусора.

Во многих случаях эта модель работает, но иногда класс выполняет некото­рые операции, требующие завершающих действий. Как упоминалось в главе 5, вы не знаете, когда будет вызван сборщик мусора и произойдет ли это вообще. Поэтому, если в классе должны выполняться действия по очистке, вам придется написать для этого особый метод и сделать так, чтобы программисты-клиенты знали о необходимости вызова этого метода. Более того, как описано в главе 10, вам придется предусмотреть возможные исключения и выполнить завершаю­щие действия в секции finally.

Представим пример системы автоматизированного проектирования, которая рисует на экране изображения:

//: reusing/CADSystem.java // Обеспечение необходимого завершения package reusing:

import static net.mindview util.Print.*;

class Shape {

Shape(int i) { print("Конструктор Shape"); } void disposed { print("Завершение Shape"); }

'}

class Circle extends Shape { Circle(int i) {

super(i),

print("Рисуем окружность Circle");

}

void disposeO {

print("Стираем окружность Circle"); super. disposeO;

}

}

class Triangle extends Shape { Triangle(int i) { super(i);

print("Рисуем треугольник Triangle");

}

void disposeO {

print("Стираем треугольник Triangle"); super.disposeO;

}

}

class Line extends Shape { private int start, end; Line(int start, int end) { super(start); this.start = start; this.end = end;

print("Рисуем линию Line: " + start + ", " + end);

}

void disposeO {

print("Стираем линию Line: " + start + ", " + end). super.disposeO;

}

public class CADSystem extends Shape { private Circle c; private Triangle t; private Line[] lines = new Line[3], public CADSystem(int i) { super(i + 1).

for(int j = 0, j < lines length; j++) lines[j] = new Line(j. j*j), с = new Circled), t = new Triangle(l), print("Комбинированный конструктор").

}

void disposed {

print("CADSystem.dispose()"); // Завершение осуществляется в порядке, // обратном порядку инициализации t disposed; с.disposed;

for(int i = lines length - 1; i >=0; i--)

lines[i] .disposed; super disposed;

}

public static void main(String[] args) { CADSystem x = new CADSystem(47), try {

// Код и обработка исключений. } finally {

х disposed,

}

}

} /* Output: Конструктор Shape Конструктор Shape Рисуем линию Line- 0, 0 Конструктор Shape Рисуем линию Line- 1. 1 Конструктор Shape Рисуем линию Line- 2, 4 Конструктор Shape Рисуем окружность Circle Конструктор Shape Рисуем треугольник Triangle Комбинированный конструктор CADSystem. disposed Стираем треугольник Triangle Завершение Shape Стираем окружность Circle Завершение Shape Стираем линию Line: 2, 4 Завершение Shape Стираем линию Line: 1, 1 Завершение Shape Стираем линию Line 0. 0 Завершение Shape Завершение Shape *///.-

Все в этой системе является некоторой разновидностью класса Shape (кото­рый, в свою очередь, неявно наследует от корневого класса Object). Каждый класс переопределяет метод dispose() класса Shape, вызывая при этом версию метода из базового класса с помощью ключевого слова super. Все конкретные классы, унаследованные от Shape — Circle, Triangle и Line, имеют конструкторы, которые просто выводят сообщение, хотя во время жизни объекта любой метод может сделать что-то, требующее очистки. В каждом классе есть свой собствен­ный метод dispose(), который восстанавливает ресурсы, не связанные с памя­тью, к исходному состоянию до создания объекта.

В методе main() вы можете заметить два новых ключевых слова, которые бу­дут подробно рассмотрены в главе 10: try и finally. Ключевое слово try показыва­ет, что следующий за ним блок (ограниченный фигурными скобками) являетсязащищенной секцией.Код в секции finally выполняется всегда, независимо от того, как прошло выполнение блока try. (При обработке исключений можно выйти из блока try некоторыми необычными способами.) В данном примере секция finally означает: «Что бы ни произошло, в конце всегда вызывать метод x.dispose()».

Также обратите особое внимание на порядок вызова завершающих методов для базового класса и объектов-членов в том случае, если они зависят друг от друга. В основном нужно следовать тому же принципу, что использует компи­лятор С++ при вызове деструкторов: сначала провести завершающие действия для вашего класса в последовательности, обратной порядку их создания. (Обычно для этого требуется, чтобы элементы базовых классов продолжали су­ществовать.) Затем вызываются завершающие методы из базовых классов, как и показано в программе.

Во многих случаях завершающие действия не являются проблемой; доста­точно дать сборщику мусора выполнить свою работу. Но уж если понадобилось провести их явно, сделайте это со всей возможной тщательностью и вниманием, так как в процессе сборки мусора трудно в чем-либо быть уверенным. Сборщик мусора вообще может не вызываться, а если он начнет работать, то объекты бу­дут уничтожаться в произвольном порядке. Лучше не полагаться на сборщик мусора в ситуациях, где дело не касается освобождения памяти. Если вы хотите провести завершающие действия, создайте для этой цели свой собственный ме­тод и не полагайтесь на метод finalize().

Report Page