Выбрать главу

Теперь мы можем усовершенствовать класс Vehicle, добавив в него конструктор, в котором будут автоматически инициализироваться поля passengers, fuelcap и mpg при построении объекта. Обратите особое внимание на то, каким образом создаются объекты типа Vehicle. // Добавление конструктора. class Vehicle { int passengers; // количество пассажиров int fuelcap; // емкость топливного бака int mpg; // потребление топлива в милях на галлон // Это конструктор класса Vehicle. Vehicle(int р, int f, int m) { passengers = p; fuelcap = f; mpg = m; } // возвратить дальность действия транспортного средства int range() { return mpg * fuelcap; } // рассчитать объем топлива, необходимого транспортному // средству для преодоления заданного расстояния double fuelneeded(int miles) { return (double) miles / mpg; } } class VehConsDemo { public static void main(String args[]) { // сконструировать полностью объекты транспортных средств Vehicle minivan = new Vehicle(7, 16, 21); Vehicle sportscar = new Vehicle(2, 14, 12); double gallons; int dist = 252; gallons = minivan.fuelneeded(dist); System.out.println("To go " + dist + " miles minivan needs " + gallons + " gallons of fuel."); gallons = minivan.fuelneeded(dist); System.out.println("To go " + dist + " miles sportscar needs " + gallons + " gallons of fuel."); } }

При создании объекты minivan и sportscar инициализируются конструктором Vehicle (). Каждый такой объект инициализируется параметрами, указанными в конструкторе его класса. Например, в строке кода Vehicle minivan = new Vehicle(7, 16, 21);

значения 7, 16 и 21 передаются конструктору Vehicle () в качестве параметров при создании нового объекта minivan с помощью оператора new.

В итоге копии переменных passengers, fuelcap и mpg в объекте minivan будут содержать значения 7, 16 и 21 соответственно. Рассмотренная здесь версия программы дает такой же результат, как и ее предыдущая версия. Еще раз об операторе new

Теперь, когда вы ближе ознакомились с классами и их конструкторами, вернемся к оператору new, чтобы рассмотреть его более подробно. Ниже приведена общая форма этого оператора в контексте присваивания. переменная_класса = new имя_класса{список_аргументов)

где переменнаякласса обозначает тип переменной создаваемого класса, а имякласса — конкретное имя класса, реализуемого в виде экземпляра его объекта. Имя класса и списокаргументов в скобках, который может быть пустым, обозначают конструктор этого класса. Если в классе не определен его собственный конструктор, то в операторе new будет использован конструктор, предоставляемый в Java по умолчанию. Следовательно, оператор new может быть использован для создания объекта, относящегося к классу любого типа. Оператор new возвращает ссылку на вновь созданный объект, который получает переменнаякласса в результате присваивания в данной форме записи.

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

Как было показано выше, при использовании оператора new свободная память для создаваемых объектов динамически выделяется из доступной буферной области оперативной памяти. Разумеется, оперативная память не бесконечна, и поэтому свободно доступная память рано или поздно исчерпывается. Это может привести к неудачному выполнению оператора new из-за нехватки свободной памяти для создания требуемого объекта. Именно по этой причине одной из главных функций любой схемы динамического распределения памяти является своевременное освобождение памяти от неиспользуемых объектов, чтобы сделать ее доступной для последующего перераспределения. Во многих языках программирования освобождение распределенной ранее памяти осуществляется вручную. Например, в C++ для этой цели служит оператор delete. Но в Java применяется другой, более надежный подход: “сборка мусора”.

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

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

Существует возможность определить метод, который будет вызван непосредственно перед окончательным удалением объекта из памяти. Этот метод называется finalize(). Он позволяет убедиться, что объект больше не существует. Этот метод можно, например, использовать для закрытия файла, открытого проверяемым объектом.

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

Ниже приведена общая форма метода finalize(). protected void finalize() { // здесь указывается код метода завершения }

Ключевое слово protected является здесь спецификатором, предотвращающим обращение к методу finalizeO за пределами класса. Этот и другие спецификаторы доступа подробнее рассматриваются в главе 6.

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

Пример для опробования 4.2. Демонстрация "сборки мусора" и завершения ко^а

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

Последовательность действий

Создайте новый файл Finalize.java.

Создайте класс FDemo, как показано ниже. class FDemo { int х;

FDemo(int i) { x = i;

}

// вызывается при утилизации объекта protected void finalize() { System.out.println("Finalizing " + x); }