Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Тема 2.7 Возвращение значения из метода
Хотя реализация метода volume () переносит вычисление объема параллелепипеда внутрь класса Box, которому принадлежит этот метод, такой способ вычисления не является наилучшим. Например, что делать, если другой часть программы требуется знание объема параллелепипеда без его отображения? Более рациональный способ реализации метода volume () – вычисление объема параллелепипеда и возврат результата вызывающему объекту. Программа из листинга 2.5 – усовершенствованная версия предыдущей программы – выполняет именно эту задачу. Листинг 2.5 // Теперь метод volume() возвращает объем параллелепипеда. public class Box { public double width; public double height; public double depth; // вычисление и возвращение объема public doublevolume() { return width * height * depth; } }
public class BoxDemo4 { public static void main(String args[]) { Box myboxl = new Box(); Box mybox2 = new Box(); double vol; // присваивание значений переменным экземпляра myboxl myboxl.width = 10; myboxl.height = 20; myboxl.depth = 15; // присваивание других значений переменным экземпляра mybox2 mybox2.width = 3; mybox2.height = 6; mybox2.depth = 9; // получение объема первого параллелепипеда vol = myboxl.volume(); vol = myboxl.volume(); System.out.println(" Объемравен " + vol); // получение объема второго параллелепипеда vol = mybox2.volume(); System.out.println(" Объем равен " + vol); } } Как видите, вызов метода volume () выполняется в правой части оператора присваивания. Правой частью этого оператора является переменная, в данном случае vol, которая будет принимать значение, возвращенное методом volume (). Таким образом, после выполнения такого оператора: vol = myboxl.volume (); значение myboxl.volume () равно 3000, и этот объем сохраняется в переменной vol. При работе с возвращаемыми значениями следует учитывать два важных обстоятельства. 1). Тип данных, возвращаемых методом, должен быть совместим с возвращаемым типом, указанным методом. Например, если возвращаемым типом какого-либо метода является boolean, нельзя возвращать целочисленное значение. 2). Переменная, принимающая возвращенное методом значение (такая как vol в данном случае), также должна быть совместима с возвращаемым типом, указанным для метода. Предыдущую программу можно было бы записать в несколько более эффективной форме, поскольку в действительности переменная vol совершенно не нужна. Обращение к методу volume () можно было бы использовать в операторе println () непосредственно, как в следующей строке кода: System.out.println(" Объем равен " + myboxl.volume()); В этом случае при выполнении оператора println() метод myboxl.volume() будет вызываться автоматически, а возвращаемое им значение будет передаваться методу println ().
Задание: Измените в нашем классе Figure метод вычисляющий периметр прямоугольника так, чтобы возвращаемый тип был double. Тема 2.8 Добавление метода, принимающего параметры
Хотя некоторые методы не нуждаются в параметрах, большинство требует их передачи. Параметры позволяют обобщать метод. То есть метод с параметрами может работать с различными данными и/или применяться в ряде несколько различных ситуаций. В качестве иллюстрации рассмотрим очень простой пример. Ниже показан метод, который возвращает квадрат числа 10. public int square () { Хотя этот метод действительно возвращает 102, его применение очень ограничено. Однако если его изменить так, чтобы он принимал параметр, как показано в следующем примере, метод square () может стать значительно более полезным. public int square(int i) { Теперь метод square () будет возвращать квадрат любого значения, с которым он вызван. То есть теперь метод square () является методом общего назначения, который может вычислять квадрат любого целочисленного значения, а не только числа 10. Приведем примеры: int х, у; В первом обращении к методу square () значение 5 будет передано параметру i. Во втором обращении параметр i примет значение, равное 9. Третий вызов метода передает значение переменной у, которое в этом примере составляет 2. Как видно из этих примеров, метод square () способен возвращать квадрат любых переданных ему данных. Важно различать два термина: параметр и аргумент. Параметр – это переменная, определенная методом, которая принимает значение при вызове метода. Например, в методе square () параметром является i. Аргумент – это значение, передаваемое методу при его вызове. Например, aquare (100) передает 100 в качестве аргумента. Внутри метода square () параметр i получает это значение. Методом с параметрами можно воспользоваться для усовершенствования класса Box. В предшествующих примерах размеры каждого параллелепипеда нужно было устанавливать отдельно, используя последовательность операторов вроде следующей: myboxl.width = 10; Хотя этот код работает, он не очень удобен по двум причинам. Во-первых, он громоздок и чреват ошибками. Например, вполне можно забыть определить один из размеров. Во-вторых, в правильно спроектированных Java-программах доступ к переменным экземпляра должен осуществляться только через методы, определенные их классом. В будущем поведение метода можно изменить, но нельзя изменить поведение раскрытой переменной экземпляра. Поэтому более рациональный подход установки размеров параллелепипеда – создание метода, который принимает размеры параллелепипеда в виде своих параметров и соответствующим образом устанавливает значение каждой переменной экземпляра. Эта концепция реализована в приведенной ниже программе листинг 2.6.
Листинг 2.6. // Эта программа использует метод с параметрами. public class Box { public double width; public double height; public double depth; // вычисление и возвращение объема public double volume() { return width * height * depth; } // установка размеров параллелепипеда public void setDim(double w, double h, double d) { width = w; height = h; depth = d; } }
public class BoxDemo5 { public static void main(String args[]) { Box myboxl = new Box(); Box mybox2 = new Box(); double vol; // инициализация каждого экземпляра Box myboxl.setDim(10, 20, 15); mybox2.setDim(3, 6, 9); // получение объема первого параллелепипеда vol = myboxl.volume(); System.out.println(" Объемравен " + vol); // получение объема второго параллелепипеда vol = mybox2.volume(); System.out.println(" Объем равен " + vol); } } Как видите, метод setDim () использован для установки размеров каждого параллелепипеда. Например, при выполнении такого оператора: myboxl.setDim(10, 20, 15); значение 10 копируется в параметр w, 20 – в h и 15 – в d. Затем внутри метода setDim () значения w, h и d присваиваются соответственно переменным width, height и depth. Многим читателям представленные в предшествующих разделах концепции будут знакомы. Однако если вы еще не знакомы с такими понятиями, как вызовы методов, аргументы и параметры, можете немного поэкспериментировать с ними, прежде чем продолжить изучение материала, изложенного в последующих разделах. Концепции вызова метода, параметров и возвращаемых значений являются основополагающими в программировании на языке Java.
Задание: Создайте в нашем классе Figure метод изменяющий начальные значения размеров прямоугольника. Тема 2.9 Конструкторы 2.9.1 Конструкторы без параметров
Инициализация всех переменных класса при каждом создании его экземпляра может оказаться утомительным процессом. Даже при добавлении функций, предназначенных для увеличения удобства работы, таких как setDim (), было бы проще и удобнее, если бы все действия по установке переменных выполнялись при первом создании объекта. Поскольку необходимость инициализации возникает столь часто, Java позволяет объектам выполнять собственную инициализацию при их создании. Эта автоматическая инициализация осуществляется с помощью конструктора. Конструктор инициализирует объект непосредственно во время создания. Его имя совпадает с именем класса, в котором он находится, а синтаксис аналогичен синтаксису метода. Как только он определен, конструктор автоматически вызывается непосредственно после создания объекта, перед завершением выполнения операции new. Конструкторы выглядят несколько непривычно, поскольку не имеют ни возвращаемого типа, ни даже типа void. Это обусловлено тем, что неявно заданный возвращаемый тип конструктора класса – тип самого класса. Именно конструктор инициализирует внутреннее состояние объекта так, чтобы код, создающий экземпляр, с самого начала содержал полностью инициализированный, пригодный к использованию объект. Пример класса Box можно изменить, чтобы значения размеров параллелепипеда присваивались при конструировании объекта. Для этого потребуется заменить метод setDim () конструктором. Вначале определим простой конструктор, который просто устанавливает одинаковые значения размеров для всех параллелепипедов. Эта версия программы приведена в листинге 2.7. Листинг 2.7 // Эта программа содержит конструктор public class Box { public double width; public double height; public double depth; // Это конструктор класса Box. public Box() { System.out.println(" Конструирование объекта Box" ); width = 10; height = 10; depth = 10; }
// вычисление и возвращение объема public double volume() { return width * height * depth; } // установкаразмеровпараллелепипеда public void setDim(double w, double h, double d) { width = w; height = h; depth = d; } }
public class BoxDemo5 { public static void main(String args[]) { Box myboxl = new Box(); Box mybox2 = new Box(); double vol; // инициализация каждого экземпляра Box myboxl.setDim(10, 20, 15); mybox2.setDim(3, 6, 9); // получение объема первого параллелепипеда vol = myboxl.volume(); System.out.println(" Объемравен " + vol); // получение объема второго параллелепипеда vol = mybox2.volume(); System.out.println(" Объем равен " + vol); } } Эта программа генерирует следующий вывод: Конструирование объекта Box Как видите, и myboxl, и mybox2 были инициализированы конструктором Box () при их создании. Поскольку конструктор присваивает всем параллелепипедам одинаковые размеры 10x10x10, и myboxl, и mybox2 будут иметь одинаковый объем. Оператор println () внутри конструктора Box() служит исключительно иллюстративным целям. Большинство конструкторов не выводят никакой информации, а лишь выполняют инициализацию объекта. Прежде чем продолжить, еще раз рассмотрим операцию new. Как вы уже знаете, при распределении памяти для объекта используют следующую общую форму: переменная_класса = new имя_класса(); Теперь вам должно быть ясно, почему после имени класса требуются круглые скобки. В действительности этот оператор вызывает конструктор класса. Таким образом, в строке: Box myboxl = new Вох(); операция new Box () вызывает конструктор Box (). Если конструктор класса не определен явно, Java создает для класса конструктор, который будет использоваться по умолчанию. Именно поэтому приведенная строка кода работала в предшествующих версиях класса Box, в которых конструктор не был определен. Конструктор, используемый по умолчанию, инициализирует все переменные экземпляра нулевыми значениями. Зачастую конструктора, используемого по умолчанию, вполне достаточно для простых классов, чего обычно нельзя сказать о более сложных. Как только конструктор определен, конструктор, заданный по умолчанию, больше не используется.
Задание: Создайте в нашем классе Figure конструктор без параметров, задающий начальные значения для прямоугольника.
2.9.2 Конструкторы с параметрами
Хотя в предыдущем примере конструктор Box () инициализирует объект Box, он не особенно полезен – все параллелепипеды получают одинаковые размеры. Следовательно, необходим способ конструирования объектов Box с различными размерами. Простейшее решение этой задачи – добавление к конструктору параметров. Как легко догадаться, это делает конструктор значительно более полезным. Например, следующая версия класса Box (листинг 2.8) определяет конструктор с параметрами, который устанавливает размеры параллелепипеда в соответствии со значениями этих параметров. Обратите особое внимание на способ создания объектов Box. Листинг 2.8 //В этой программе класс Box использует конструктор с параметрами public class Box { public double width; public double height; public double depth; // Этоконструкторкласса Box. Box(double w, double h, double d) { width = w; height = h; depth = d; }
// вычисление и возвращение объема public double volume() { return width * height * depth; } // установкаразмеровпараллелепипеда public void setDim(double w, double h, double d) { width = w; height = h; depth = d; } }
public class BoxDemo5 { public static void main(String args[]) { Box myboxl = new Box(); Box mybox2 = new Box(); doublevol; // инициализация каждого экземпляра Box myboxl.setDim(10, 20, 15); mybox2.setDim(3, 6, 9); // получение объема первого параллелепипеда vol = myboxl.volume(); System.out.println(" Объемравен " + vol); // получение объема второго параллелепипеда vol = mybox2.volume(); System.out.println(" Объем равен " + vol); } } Как видите, инициализация каждого объекта выполняется в соответствии со значениями, указанными в параметрах его конструктора. Например, в следующей строке: Box myboxl = new Box(10, 20, 15); значения 10, 20 и 15 передаются конструктору Box () при создании объекта с помощью операции new. Таким образом, копии переменных width, height и depth будут содержать соответственно значения 10, 20 и 15.
Задание: Создайте в нашем классе Figure конструктор с параметрами. 2.9.3 Ключевое слово this
Иногда будет требоваться, чтобы метод ссылался на вызвавший его объект. Чтобы это было возможно, в Java определено ключевое слово this. Оно может использоваться внутри любого метода для ссылки на текущий объект. То есть this всегда служит ссылкой на объект, для которого был вызван метод. Ключевое слово this можно использовать везде, где допускается ссылка на объект типа текущего класса. Для пояснения рассмотрим следующую версию конструктора Box (): // Избыточное применение ключевого слова this. Эта версия конструктора Box () действует точно так же, как предыдущая. Применение ключевого слова this избыточно, но совершенно правильно. Внутри метода Box () ключевое слово this всегда будет ссылаться на вызывающий объект. Хотя в данном случае это и излишне, в других случаях, один из которых рассмотрен в следующем разделе, ключевое слово this весьма полезно.
2.9.4 Сокрытие переменной экземпляра
Как вы знаете, в Java не допускается объявление двух локальных переменных с одним и тем же именем в одной и той же или во включающих одна другую областях определения. Интересно отметить, что могут существовать локальные переменные, в том числе формальные параметры методов, которые перекрываются с именами переменных экземпляра класса. Однако когда имя локальной переменной совпадает с именем переменной экземпляра, локальная переменная скрывает переменную экземпляра. Именно поэтому внутри класса Box переменные width, height и depth не были использованы в качестве имен параметров конструктора Box (). В противном случае переменная width ссылалась бы на формальный параметр, скрывая переменную экземпляра width. Хотя обычно проще использовать различные имена, существует и другой способ выхода из подобной ситуации. Поскольку ключевое слово this позволяет ссылаться непосредственно на объект, его можно применять для разрешения любых конфликтов пространства имен, которые могут возникать между переменными экземпляра и локальными переменными. Например, ниже показана еще одна версия метода Box (), в которой имена width, height и depth использованы в качестве имен параметров, а ключевое слово this служит для обращения к переменным экземпляра по этим же именам. // Этот код служит для разрешения конфликтов пространства имен.publicBox(doublewidth, doubleheight, doubledepth) { Небольшое предостережение: иногда подобное применение ключевого слова this может приводить к недоразумениям, и некоторые программисты стараются не применять имена локальных переменных и параметров, скрывающие переменные экземпляров. Конечно, множество программистов придерживаются противоположного мнения и считают целесообразным в целях облегчения понимания программ использовать одни и те же имена, а для предотвращения скрытия переменных экземпляров применяют ключевое слово this.
Задание: Измените в нашем классе Figure конструктор с параметрами (имена параметров и полей совпадают) используя ключевое слово this. Тема 2.10 Сборка мусора
Поскольку распределение памяти для объектов осуществляется динамически посредством операции new, у читателей может возникнуть вопрос, как уничтожаются такие объекты и как их память освобождается для последующего распределения. В некоторых языках, подобных С++, динамически распределенные объекты нужно освобождать вручную с помощью операции delete. В Java применяется другой подход. Освобождение памяти выполняется автоматически. Используемая для выполнения этой задачи технология называется сборкой мусора. Процесс проходит следующим образом: при отсутствии каких-либо ссылок на объект программа заключает, что этот объект больше не нужен, и занимаемую объектом память можно освободить. В Java не нужно явно уничтожать объекты, как это делается в С++. Во время выполнения программы сборка мусора выполняется только изредка (если вообще выполняется). Она не будет выполняться лишь потому, что один или несколько объектов существуют и больше не используются. Более того, в различных реализациях системы времени выполнения Java могут применяться различные подходы к сборке мусора, но в большинстве случаев при написании программ об этом можно не беспокоиться. Иногда при уничтожении объект должен будет выполнять какое-либо действие. Например, если объект содержит какой-то ресурс, отличный от ресурса Java (вроде файлового дескриптора или шрифта), может требоваться гарантия освобождения этих ресурсов перед уничтожением объекта. Для подобных ситуаций Java предоставляет механизм, называемый финализацией. Используя финализацию, можно определить конкретные действия, которые будут выполняться непосредственно перед удалением объекта сборщиком мусора. Чтобы добавить в класс средство выполнения финализации, достаточно определить метод finalize (). Среда времени выполнения Java вызывает этот метод непосредственно перед удалением объекта данного класса. Внутри метода finalize () нужно указать те действия, которые должны быть выполнены перед уничтожением объекта. Сборщик мусора запускается периодически, проверяя наличие объектов, на которые отсутствуют ссылки как со стороны какого-либо текущего состояния, так и косвенные ссылки через другие ссылочные объекты. Непосредственно перед освобождением ресурсов среда времени выполнения Java вызывает метод finalize () по отношению к объекту. Общая форма метода finalize () имеет следующий вид: protected void finalize ( ) { В этой синтаксической конструкции ключевое слово protected – спецификатор, который предотвращает доступ к методу finalize () со стороны кода, определенного вне его класса. Важно понимать, что метод finalize () вызывается только непосредственно перед сборкой мусора. Например, он не вызывается при выходе объекта за рамки области определения. Это означает, что неизвестно, когда будет – и, даже будет ли вообще – выполняться метод finalize (). Поэтому программа должна предоставлять другие средства освобождения используемых объектом системных ресурсов и тому подобного. Нормальная работа программы не должна зависеть от метода finalize (). Популярное:
|
Последнее изменение этой страницы: 2016-05-30; Просмотров: 681; Нарушение авторского права страницы