Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
41
Добавлен:
12.05.2015
Размер:
624.64 Кб
Скачать

Возврат объектов

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

// Возврат объекта,

class Test {

int a ;

Test(int i) {

a = i;

}

Test incrByTen() {

Test temp = new Test(a+10);

return temp;

}

}

class RetOb {

public static void main(String args[]) {

Test ob1 = new Test (2);

Test ob2;

ob2 = ob1.incrByTen() ;

System.out.println("obi.a: " + obi.a);

System.out.println("ob2.a: " + ob2.a);

ob2 = ob2.incrByTen();

System.out.println("ob2.а после повторного увеличения: " + ob2.a);

}

}

Вывод, сгенерированный этой программой:

obl.a: 2

оЬ2.а: 12

оЬ2.а после 'повторного увеличения: 22

Каждый раз, когда incrByTen о вызывается, создается новый объект, и ссылка на него возвращается вызывающей подпрограмме.

Из предыдущей программы можно сделать следующий важный вывод: т. к. все объекты распределяются динамически с помощью операции new, вас не должен беспокоить выход объекта из области его видимости, потому что метод, в котором он был создан, завершается. Объект продолжает существо­вать, пока где-то в вашей программе присутствует ссылка на него. Когда же ссылок нет, то в следующем сеансе сборки "мусора" объект будет утилизи­рован.

Рекурсия

Java поддерживает рекурсию. Рекурсия – это процесс определения чего-то в терминах самого себя. Что касается Java-программирования, то рекурсия – это атрибут, который позволяет методу вызвать самого себя. Такой метод называют рекурсивным.

Классический пример рекурсии – вычисление факториала числа. Фактори­ал числа N есть произведение всех целых чисел между 1 и N. Например, факториал 3 равен 1*2*3 или 6. Ниже показано, как факториал может быть вычислен при помощи рекурсивного метода:

// Простой пример рекурсии,

class Factorial { // это рекурсивная функция

int fact (int n) {

int result ;

if(n==l) return 1 ;

result = fact(n-l) * n ;

return result ;

}

}

class Recursion { . .

public static void main(String args[]) {

Factorial f = new Factorial();

System.out.println("Факториал 3 равен " + f.fact(3)) ;

System.out.println("Факториал 4 равен " + f.fact(4)) ;

System.out.println("Факториал 5 равен " + f.fact(5)) ;

}

}

Вывод этой программы:

Факториал 3 равен 6

Факториал 4 равен 24

Факториал 5 равен 120

Если вы не знакомы с рекурсивными методами, то операция fact () может показаться немного запутанной. Вот как она работает. Когда метод fact () вызывается с параметром 1, функция возвращает I, иначе она возвращает произведение fact(n-i)*n. Чтобы оценить это выражение, fact () вызывает­ся с параметром п-i. Этот процесс повторяется до тех пор, пока п не станет равным 1, и вызов метода не начнет возврат.

Чтобы лучше понять, как работает метод facto, прокрутим короткий при­мер. Когда вы вычисляете факториал 3, первый вызов fact () приведет ко второму вызову – с аргументом 2. Это обращение, в свою очередь, вызовет fact () в третий раз – с аргументом 1, а затем возвратит значение 1, которое потом умножается на 2 (значение п во втором обращении). Этот результат (который равен 2) затем возвращается первоначальному вызову fact () и умножается на 3 (первоначальное значение п). Вся это процедура приводит к окончательному результату 6. Было бы интересно вставить в fact () утверж­дения с println (), которые покажут, на каком уровне каждый вызов нахо­дится и каковы промежуточные ответы.

Когда метод вызывает сам себя, новым локальным переменным и парамет­рам выделяется память в стеке, и код метода выполняется с этими новыми переменными от начала стека. Рекурсивный вызов не делает новой копии метода. Обновляются только параметры. Когда каждый рекурсивный вызов выполняет возврат, старые локальные переменные и параметры удаляются из стека, и выполнение возобновляется в точке вызова внутри метода.

Рекурсивные версии многих подпрограмм могут выполняться немного мед­леннее, чем итерационный эквивалент, из-за добавления дополнительных вызовов функций. Частые рекурсивные обращения к методу могут вызывать переполнение стека. Поскольку память для параметров и локальных пере­менных находится в стеке, и каждый новый вызов создает новую копию этих переменных, возможно, что стек может быть исчерпан. Если это про­исходит, исполнительная система Java вызовет исключение.

Главное преимущество рекурсивных методов состоит в том, что их можно использовать для создания более ясных и простых версий некоторых алго­ритмов (по сравнению с их итерационными "родственниками"). Например, алгоритм быстрой сортировки весьма трудно реализовать итерационным способом. Некоторые проблемы, особенно имеющие отношение к искусст­венному интеллекту, кажется, удобно решать рекурсивно. Наконец, некото­рым людям кажется, что рекурсивное мышление легче, чем итеративное.

При записи рекурсивных методов следует где-то использовать оператор if, чтобы вынудить метод осуществить возврат без выполнения рекурсивного вызова. Если вы этого не сделаете, то после вызова метода, он никогда не будет возвращать управления. Это самая распространенная ошибка в работе с рекурсией. Свободно используйте утверждение println о во время разра­ботки для наблюдения за происходящим и выполняйте аварийное заверше­ние, если видите, что сделали ошибку.

Ниже приведен еще один пример рекурсии. Рекурсивный метод printArray () печатает 10 первых элементов массива values.

// Другой пример использования рекурсии.

class RecTest {

int values[] ;

RecTest(int i) {

values = new intfi] ;

}

// отобразить массив рекурсивно

void printArray (int i) {

if(i==0) return ;

else printArray(i-1) ;

System.out.println("[" + (i-1) + "]" + values[i-1] ; } } . .

class Recursion2 {

public static void main (String ' args []) {

RecTest ob = new RecTest (10) ;

int I ;

for(i=0; i<10; i++) ob.values[i] = I ;

ob. printArray (10) ;

}

}

Эта программа генерирует следующий вывод:

[0] 0

[1] 1 . .

[2] 2 :

[3] 3

[4] 4

[5] 5 .

[6] 6

[7] 7

[8] 8

[9] 9

Соседние файлы в папке JavaLit