#java #algorithm #recursion #methods
#java #алгоритм #рекурсия #методы
Вопрос:
Может кто-нибудь объяснить, что происходит в этом коде. Код завершается только при передаче -1. До этого он продолжает запрашивать ввод данных пользователем. И только после завершения он выводит значения, кратные 3, из входных значений. Я в замешательстве, где все значения x сохраняются до завершения.
public class Recursion {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
multipleThree(in);
}//end of main
public static void multipleThree(Scanner in) {
System.out.println("Enter the list(-1 to terminate):");
int x = in.nextInt();
if (x == -1) {
return;
} else {
multipleThree(in);
if (x % 3 == 0)
System.out.println(x " is divisible by 3");
}//end of else
}//end of method
}//end of class
Комментарии:
1. каждый раз, когда вызывается метод, некоторая память резервируется для его переменных и параметров (часто называемых фреймом) — поэтому каждый вызов имеет свою собственную версию переменных — поскольку
int x
объявляется переменная внутри метода, она сохраняется в этой памяти (фрейме). Не только актуально для рекурсивных вызовов, но и является ключевым для работы рекурсивных методов. [поскольку вывод выполняется после вызова tomultipleThree
, он будет выполнен только после возврата вызовов]
Ответ №1:
Я в замешательстве, где все значения x сохраняются до завершения.
Они хранятся в стеке вызовов.
В начале стек вызовов имеет только main
. Затем main
вызывает multipleThree
. Это помещает новый фрейм в стек вызовов. Фрейм будет хранить информацию о том, куда продвинулся этот вызов multipleThree
, какие существуют локальные переменные и т.д.
Допустим, вы ввели 3. x
, который хранится во фрейме, который в настоящее время является вершиной стека. else
Ветвь выполняется и multipleThree
вызывается снова, поэтому новый фрейм помещается в стек вызовов. Обратите внимание, что мы еще не закончили с первым вызовом multipleThree
. Мы можем вернуться к нему, когда закончим выполнение этого второго вызова multipleThree
. Помните, что введенные вами 3 все еще хранятся в стеке вызовов.
Допустим, далее вы ввели 5, происходит то же самое — число 5 сохраняется в верхней части стека, затем при повторном вызове запускается новый кадр multipleThree
(теперь это уже третий раз).
Наконец, вы вводите -1. На данный момент стек выглядит следующим образом:
multipleThree (x = -1)
multipleThree (x = 5)
multipleThree (x = 3)
main
Вы можете увидеть это в отладчике в вашей IDE. например, в IntelliJ IDEA
Поскольку вы ввели -1, этот вызов multipleThree
фактически завершается, поскольку он достигает return
оператора. Теперь открывается верхняя часть стека, и мы возвращаемся к выполнению второго вызова multipleThree
. Теперь стек выглядит так:
multipleThree (x = 5)
multipleThree (x = 3)
main
Во втором вызове помните, что x равно 5 — не делится на 3, поэтому мы ничего не делаем. Теперь мы закончили со вторым вызовом multipleThree
, поэтому стек снова открывается:
multipleThree (x = 3)
main
Теперь мы, наконец, возвращаемся к выполнению первого вызова multipleThree
, когда x
равно 3 . 3 делится на 3, поэтому мы его печатаем. Теперь мы закончили с первым вызовом multipleThree
, поэтому мы также удаляем его из стека.