— Привет, Амиго. Сегодня Билаабо расскажет тебе, что такое рекурсия.

Как ты знаешь, в Java одни методы вызывают другие методы. При этом, при вызове метода, в него передаются конкретные значения аргументов, а во время его работы локальные переменные метода принимают некоторые значения.
— Ага.
— И как ты знаешь, внутренние переменные разных методов независимы друг от друга.
— Ага.
— Так вот, представь ситуацию, когда метод может вызвать сам себя. Именно она называется рекурсией. Пример:
public static void main(String[] args)
{
countDown(10);
}
public static void countDown(int x)
{
if (x <=0)
System.out.println("Boom!");
else
{
System.out.println(x);
countDown(x - 1);
}
}
10
9
8
7
6
5
4
3
2
1
Boom!
— Честно говоря, вижу, что метод в коде сам себя вызывает, но не понимаю, что именно при этом происходит.
— Да примерно то же, что и при вызове другого метода.
— Нет, я спрашиваю, что происходит с переменными? С их значениями? И как мы выходим из метода? Или мы выходим из всех сразу?
— Господи. Да все гораздо проще. Представь что метод, который вызывает сам себя, размножили много раз. Тогда будет аналогичная ситуация:
Рекурсивный вызов метода | Что происходит «на самом деле» |
---|---|
|
|
Вывод на экран: | Вывод на экран: |
---|---|
|
|
Т.е. каждый раз при вызове метода (даже самого себя) создаются новые переменные, которые хранят данные для этого метода. Никаких общих переменных нет.
При каждом вызове в памяти появляется еще одна копия аргументов метода, но уже с новыми значениями. При возвращении в старый метод, там используются его переменные. Т.е. при рекурсии фактически мы вызываем другой метод, но с таким же кодом как наш!
— Ясно. А как работает выход из этих методов? Можно пример?
— Ладно. Один пример стоит тысячи слов. Вот тебе пример:
Рекурсивный вызов метода | Что происходит «на самом деле» |
---|---|
|
|
Вывод на экран: | Вывод на экран: |
---|---|
|
|
— Ок. Вроде понял. А зачем нужна рекурсия?
— Есть очень много задач, которые разбиваются на отдельные подзадачи, идентичные первоначальной задаче. Например, надо обойти все элементы XML-дерева. У каждого элемента может быть несколько дочерних элементов, а у них — свои.
Или тебе нужно вывести список файлов, которые есть в директории и все ее поддиректориях. Тогда ты пишешь метод, который выводит файлы текущей директории, а потом для получения файлов всех поддиректорий вызываешь его же, но с другим параметром – поддиректорией.
Пример:
public static void main(String[] args)
{
printAllFiles(new File("c:/windows/"));
}
public static void printAllFiles(File dir)
{
for (File file : dir.listFiles())
{
if (file.isDirectory())
printAllFiles(file);
else
System.out.println(file.getAbsolutePath());
}
}
Строка 8 – получаем список всех файлов (и директорий) в директории dir.
Строки 10-11 – если файл на самом деле директория, то для вывода ее файлов опять вызываем printAllFiles, но уже с другим параметром – поддиректорией.
Строка 13 – выводим имя текущего файла.
— Ок. Вроде понял. Спасибо, Билаабо.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ