递归调用是方法在自身内部直接或间接调用自身,必须包含基线条件(终止条件)和递归步骤(缩小规模的子问题),依托调用栈展开与回退执行,常见错误有缺失终止条件、条件设计不当、参数未收敛及深度过大导致性能下降。
递归调用,就是方法在自己的方法体内部直接或间接地调用自身。它不是循环,但能实现重复逻辑;它的本质是函数调用栈的自然展开与回退。
缺一不可,否则会崩溃或死循环:
n == 0 或 n == 1 就直接返回 1,不再继续调用。factorial(n) 返回 n * factorial(n - 1),问题规模每次
减 1。Java 每次调用方法,都会在虚拟机栈中创建一个独立的栈帧,保存参数、局部变量和返回地址。递归时这个过程连续发生:
factorial(4) → 压入第 1 个栈帧factorial(3) → 压入第 2 个栈帧factorial(2)、factorial(1) → 分别压入第 3、第 4 个栈帧factorial(1),满足基线条件,返回 1 → 第 4 个栈帧弹出2 * 1 = 2,返回 → 第 3 帧弹出4 * 3 * 2 * 1 = 24
看似简洁,但容易踩坑:
StackOverflowError
n == 2 却传入负数,可能永远无法命中,照样溢出factorial(n)(没变参数),等于原地打转适合天然具有“自相似”结构的问题: