Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
GoslingJava2.doc
Скачиваний:
139
Добавлен:
23.02.2016
Размер:
2.39 Mб
Скачать

2.10.1. Метод finalize

Обычно вы и не замечаете, как происходит уничтожение “осиротевших” объектов. Тем не менее класс может реализовать метод с именем finalize, который выполняется перед уничтожением объекта или при завершении работы виртуальной машины. Метод finalize дает возможность использовать удаление объекта для освобождения других, не связанных с Java ресурсов. Онобъявляетсяследующимобразом:

protected void finalize() throws Throwable {

super.finalize();

// ...

}

Роль метода finalize становится особенно существенной при работе с внешними по отношению к Java ресурсами, которые слишком важны, чтобы можно было дожидаться этапа сборки мусора. Например, открытые файлы (число которых обычно ограничено) не могут дожидаться завершающей фазы finalize— нет никакой гарантии, что объект, содержащий открытый файл, будет уничтожен сборщиком мусора до того, как израсходуются все ресурсы по открытию файлов.

Поэтому в объекты, распоряжающиеся внешними ресурсами, следует включать метод finalize, освобождающий ресурсы и предотвращающий их утечку. Кроме того, вам придется предоставить программистам возможность явного освобождения этих ресурсов. Например, в класс, который открывает файл для своих целей, следует включить метод close для закрытия файла, чтобы пользующиеся этим классом программисты могли явным образом распоряжаться количеством открытых файлов в системе.

Иногда может случиться так, что метод close не будет вызван, несмотря на то, что работа с объектом закончена. Возможно, вам уже приходилось сталкиваться с подобными случаями. Вы можете частично предотвратить “утечку файлов”, включив в класс метод finalize, внутри которого вызывается close,— таким образом можно быть уверенным, что вне зависимости от качества работы других программистов ваш класс никогда не будет поглощать открытые файлы. Вот как это может выглядеть на практике:

public class ProcessFile {

private Stream File;

public ProcessFile(String path) {

File = new Stream(path);

}

// ...

public void close() {

if (File != null) {

File.close();

File = null;

}

}

protected void finalize() throws Throwable {

super.finalize();

close();

}

}

Обратите внимание: метод close написан так, чтобы его можно было вызвать несколько раз. В противном случае, если бы метод close уже использовался ранее, то при вызове finalize происходила бы попытка повторного закрытия файла, что может привести к ошибкам.

Кроме того, в приведенном выше примере следует обратить внимание на то, что метод finalize вызывает super.finalize. Пусть это войдет у вас в привычку для всех методов finalize, которые вам придется писать. Если не использовать super.finalize, то работа вашего класса завершится нормально, но суперклассы, для которых не были выполнены необходимые завершающие действия, могут вызвать сбои. Помните, вызов super.finalize— это полезное правило, применяемое даже в том случае, если ваш класс не является расширением другого класса. Помимо того, что это послужит вам дополнительным напоминанием на будущее, вызов super.finalize в подобных ситуациях позволит в будущем породить класс, аналогичный Process File, от другого суперкласса и при этом не заботиться о переделке метода finalize.

В теле метода finalize может применяться конструкция try/catch для обработки исключений в вызываемых методах, но любые неперехваченные исключения, возникшие при выполнении метода finalize, игнорируются. Исключения подробно рассматриваются в главе 7.

Сборщик мусора может уничтожать объекты в любом порядке, а может и не уничтожать их вовсе. Память будет освобождаться в тот момент, который сборщик мусора сочтет подходящим. Отсутствие привязки к какому-то конкретному порядку позволяет сборщику мусора действовать оптимальным образом, что позволяет снизить накладные расходы на его работу. Вы можете напрямую вызвать сборщик мусора, чтобы память была освобождена раньше (см. раздел “Управление памятью”).

При завершении работы приложения вызываются методы finalize для всех существующих объектов. Это происходит независимо от того, что послужило причиной завершения; тем не менее некоторые системные ошибки могут привести к тому, что часть методов finalize не будет запущена. Например, если программа завершается по причине нехватки памяти, то сборщику мусора может не хватить памяти для поиска всех объектов и вызова их методов finalize. И все же в общем случае можно рассчитывать на то, что метод finalize будет вызван для каждого объекта.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]