Java方法的递归调用

Java方法的递归调用

方法的递归调用就是方法自身调用自身。

先看下面的例子:

public class Test {

  /**
   * 使用 for 循环实现1~n的和
   *
   * @param n 参数
   * @return int
   */
  private static int loopSum(int n) {
    int sum = 0;
    for (int i = 1; i <= n; i++) {
      sum += i;
    }
    return sum;
  }

  /**
   * 使用递归实现1~n的和
   *
   * @param n 参数
   * @return int
   */
  private static int recursionSum(int n) {
    if (n == 1) {
      return 1;
    } else {
      return n + recursionSum(n - 1);
    }
  }

  /**
   * 使用 for 循环实现1~n的乘积
   *
   * @param n 参数
   * @return int
   */
  private static int loopMultiplyValue(int n) {
    int sum = 1;
    for (int i = 1; i <= n; i++) {
      sum *= i;
    }
    return sum;
  }

  /**
   * 使用递归实现1~n的乘积
   *
   * @param n 参数
   * @return int
   */
  private static int recursionMultiplyValue(int n) {
    if (n == 1) {
      return 1;
    } else {
      return n * recursionMultiplyValue(n - 1);
    }
  }

  public static void main(String[] args) {
    int result1 = loopSum(100);
    int result2 = recursionSum(100);
    System.out.println("result1= " + result1);
    System.out.println("result2= " + result2);

    int result3 = loopMultiplyValue(6);
    int result4 = recursionMultiplyValue(6);
    System.out.println("result3= " + result3);
    System.out.println("result4= " + result4);
  }
  
}

运行结果:
方法递归调用运行结果
递归应用中有个经典的例子就是实现斐波那契数列:

public class FibonacciDemo {
     
/**
   * 计算斐波那契数列 一对兔子,第一个月不生,第二个月不生,从第三个月开始生下一对兔子 
   * 生下的那一对兔子,第一个月不生第二个月不生,从第三个月开始生下一对兔子 
   * 问:12个月后 一共有多少对兔子?
   * 示例:1 1 2 3 5 8 13 21 34 55 89 144 
   * 分析可知:从第三个月开始 month = (month - 1) + (month - 2)
   *
   * @param month 参数
   * @return int
   */
  private static int getFibonacci(int month) {
    if (month == 1) {
      return 1;
    }
    if (month == 2) {
      return 1;
    }
    return getFibonacci(month - 1) + getFibonacci(month - 2);
  }

  public static void main(String[] args) {
    System.out.println(getFibonacci(12));
  }
	
}

运行结果:
斐波那契数列执行结果
方法的递归调用适用于方法中运算的主体不变,但运行的方法参数会发生变化的场景。
注意:

  1. 递归一定要有出口,必须可以让程序可以停下;
  2. 递归次数不能过多;
  3. 构造方法,禁止递归。

以下程序因为递归没有结束的条件,所以一直压栈,没有弹栈,导致栈内存溢出错误!所以递归必须要有结束条件。

public class RecursionTest{

	public static void main(String[] args) {
		method();
	}

	private static void method() {
		//java.lang.StackOverflowError
		method(); 
	}
	
}

运行结果:
无限递归执行结果

### Java递归调用的概述 在 Java 编程语言中,递归是指函数在其定义或实现过程中直接或间接地调用了自己。这种技术对于处理能够被自然划分为相似子问题的任务特别有效[^3]。 #### 递归的工作原理 每当一个递归方法被执行,在 JVM 上下文中会创建一个新的栈帧来保存该次调用的状态信息,比如传递给它的参数以及内部使用的局部变量等。如果递归层次太深,则可能会超出虚拟机所能提供的最大栈深度限制,从而引发 `StackOverflowError` 错误[^1]。 ```java public class Factorial { public static long factorial(long number) { if (number <= 1) { // base case return 1; } else { // recursive step return number * factorial(number - 1); } } public static void main(String[] args) { try { System.out.println("Factorial of 5 is " + factorial(5)); } catch (Exception e) { System.err.println(e.getMessage()); } } } ``` 上述代码展示了如何通过递归来计算阶乘值。需要注意的是,这里设置了一个终止条件(即基本情形),这是为了避免无限循环并最终导致堆栈溢出的关键所在。 #### 防止堆栈溢出的方法 为了防止由于过度深入而引起的堆栈溢出: - **优化算法逻辑**:确保存在清晰明确的基础情况,并且每一次递归都能朝着基础情况进行简化。 - **采用尾递归转换**:虽然标准版 JDK 不支持自动将常规递归转化为更高效的尾递归形式,但在编写代码可以手动调整为尾递归模式以减少中间状态的数量。 - **迭代替代方案**:有可以通过改写程序使用显式的数据结构如队列或者栈来进行广度优先搜索(BFS)/深度优先搜索(DFS),以此代替隐含于递归之中的系统调用栈操作[^4]。 #### 自引用与类级别的递归调用注意事项 当涉及到对象之间的相互关联或者是自我复制的数据结构,应当小心谨慎地管理这些关系以免造成意外的行为。例如,在声明数组或其他容器类型作为实例字段之前要充分考虑其生命周期及其潜在影响;另外也要注意初始化顺序可能带来的副作用。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值