> 文档中心 > 【javaSE】java函数(方法)重载及函数递归

【javaSE】java函数(方法)重载及函数递归

文章目录

  • 函数的概念
    • 函数定义
    • 函数命名
  • 函数调用的执行过程
    • 实参和形参的关系(重要)
  • 函数重载
    • 函数可以重载的根本原因
  • 函数递归
    • 生活中的故事
    • 函数递归概念
    • 斐波那契数列

函数的概念

什么是函数,在java中,函数也叫方法。
函数就是一个代码片段,在程序中,我们可能经常要去实现某个功能,我们可以把这个功能实现代码单独打包起来,需要用的时候直接去调用该函数,不需要再打一次代码。
总结起来就是:

  1. 是能够模块化的组织代码(当代码规模比较复杂的时候).
  2. 做到代码被重复使用, 一份代码可以在多个位置使用.
  3. 让代码更好理解更简单.
  4. 直接调用现有方法开发, 不必重复造轮子.

比如,我们判断一个数是奇数还是偶数
正常代码是这样

public static void main2(String[] args) { int a=3; if(a%2==0){     System.out.println(a+"是偶数"); }else{     System.out.println(a+"是奇数"); }    }

那么怎么用函数实现呢

函数定义

基本语法

// 函数定义
修饰符 返回值类型 方法名称([参数类型 形参 …]){
函数体代码;
[return 返回值];
}
还是来判断一个数是奇数还是偶数

//主函数public class Test2 {    public static void main(String[] args) { int a=3; evenOrOdd(3);    }    //判断奇偶数函数    public  static void evenOrOdd(int a){ if(a%2==0){     System.out.println(a+"是偶数"); }else{     System.out.println(a+"是奇数"); }    }

运行结果
【javaSE】java函数(方法)重载及函数递归

函数命名

函数名字一般采用小驼峰命名
在实际开发中,函数命名一般都是英文命名,最好别用中文拼音命名,(可能会被鄙视看不起…)那什么是小驼峰呢,如上面判断是偶数或者奇数 evenOrOdd 第一个单词首字母小写,后面单词首字母大写。
注意

  1. 修饰符:现阶段直接使用public static 固定搭配
  2. 返回值类型:如果函数有返回值,返回值类型必须要与返回的实体类型一致,如果没有返回值,必须写成void
  3. 函数名字:采用小驼峰命名
  4. 参数列表:如果函数没有参数,()中什么都不写,如果有参数,需指定参数类型,多个参数之间使用逗号隔开
  5. 函数体:函数内部要执行的语句
  6. 在java当中,函数必须写在类当中
  7. 在java当中,函数不能嵌套定义
  8. 在java当中,函数方法声明一说

函数调用的执行过程

【函数调用过程】
调用函数—>传递参数—>找到函数地址
—>执行被调函数的函数体—>被调函数结束返回
—>回到主调函数继续往下执行

【注意事项】
定义方法的时候, 不会执行方法的代码. 只有调用的时候才会执行.
一个方法可以被多次调用.

代码示例: 计算 1! + 2! + 3! + 4! + 5!

public class TestMethod { public static void main(String[] args) { int sum = 0; for (int i = 1; i <= 5; i++) { //一次循环得到一个阶乘结果,一个一个加起来sum += fac(i); }System.out.println("sum = " + sum); }//计算某个数的阶乘public static int fac(int n) { System.out.println("计算 n 的阶乘中n! = " + n); int result = 1; for (int i = 1; i <= n; i++) { result *= i; }return result; } }// 执行结果 计算 n 的阶乘中 n! = 1 计算 n 的阶乘中 n! = 2 计算 n 的阶乘中 n! = 3 计算 n 的阶乘中 n! = 4 计算 n 的阶乘中 n! = 5 sum = 153

实参和形参的关系(重要)

形参是用来接收实参的值,形参的名字可以随意取,对函数都没有任何影响,形参只是函数在定义时需要借助的一个变量,用来保存函数在调用时传递过来的值。
看下面的一个代码

public class TestMethod { public static void main(String[] args) { int a = 10; int b = 20; swap(a, b); System.out.println("main: a = " + a + " b = " + b); }public static void swap(int x, int y) { int tmp = x; x = y; y = tmp; System.out.println("swap: x = " + x + " y = " + y); } }// 运行结果 swap: x = 20 y = 10 main: a = 10 b = 20

结果·为什么是这样呢?
实参a和b是main方法中的两个变量,其空间在main方法的栈(一块特殊的内存空间)中,而形参x和y是swap函数中的
两个变量,x和y的空间在swap方法运行时的栈中,因此:实参a和b 与 形参x和y是两个没有任何关联性的变量,在
swap方法调用时,只是将实参a和b中的值拷贝了一份传递给了形参x和y,因此对形参x和y操作不会对实参a和b产
生任何影响。在这里插入图片描述

注意:对于基础类型来说, 形参相当于实参的拷贝. 即 传值调用

函数重载

什么是函数重载呢
在编程中,我们常常需要写函数实现某些功能,而有些函数的实现功能是一样的,但参数可能不一样,我们可以给这些函数命名相同,但参数不一样,这就是函数重载。
总结:在Java中,如果多个函数的名字相同,参数列表不同,则称该几种函数被重载了。
如下代码,

public class TestMethod { public static void main(String[] args) { add(1, 2); // 调用add(int, int) add(1.5, 2.5); // 调用add(double, double) add(1.5, 2.5, 3.5); // 调用add(double, double, double) }public static int add(int x, int y) { return x + y; } public static double add(double x, double y) { return x + y; }public static double add(double x, double y, double z) { return x + y + z; } } 

为了返回某几个变量之和,可能需要返回两个int类型数据之和,或者三个int类型数据之和,或者又是浮点型数据之和,我们重载了add这个函数,这几个add函数功能都是一样的,但是参数的个数,类型,顺序会有所不同。
参数顺序不同,例如这个add(int a,double b);
———————————add(double a, int b);

注意:

  1. 方法名必须相同
  2. 参数列表必须不同(参数的个数不同、参数的类型不同、类型的次序必须不同)
  3. 与返回值类型是否相同无关
  4. 编译器在编译代码时,会对实参类型进行推演,根据推演的结果来确定调用哪个方法

函数可以重载的根本原因

在同一个作用域中不能定义两个相同名称的标识符。 比如函数中不能定义两个名字一样的变量,那为什么类中就可以定义方法名相同的方法呢?

编译器在编译Java程序时,会修改函数的名字,即是函数签名
函数签名即:经过编译器编译修改过之后方法最终的名字。具体方式:方法全路径名+参数列表+返回值类型,构成方
法完整的名字
如下图,函数double add(double, double);的函数签名(方法签名)
【javaSE】java函数(方法)重载及函数递归
【javaSE】java函数(方法)重载及函数递归

函数递归

生活中的故事

从前有坐山,山上有座庙,庙里有个老和尚给小和尚将故事,讲的就是:
"从前有座山,山上有座庙,庙里有个老和尚给小和尚讲故事,讲的就是:
“从前有座山,山上有座庙…”
“从前有座山……”

上面的两个故事有个共同的特征:自身中又包含了自己,该种思想在数学和编程中非常有用,因为有些时候,我们遇到的问题直接并不好解决,但是发现将原问题拆分成其子问题之后,子问题与原问题有相同的解法,等子问题解决之后,原问题就迎刃而解了。

函数递归概念

一个方法在执行过程中调用自身, 就称为 “递归”.
递归相当于数学上的 “数学归纳法”, 有一个起始条件, 然后有一个递推公式.,最重要的还有结束递归的条件

如 求出某个数的阶乘

public static void main(String[] args) { int n = 5; int ret = factor(n); System.out.println("ret = " + ret); }public static int factor(int n) { if (n == 1) { return 1; }return n * factor(n - 1); // factor 调用函数自身 }// 执行结果 ret = 120

程序执行过程
在这里插入图片描述
递归递归,就是先递出去,再归回来,如上图,factor(n)一个一个递出去(红线),最后遇到结束条件n==1,在一个一个归回来(绿线)

注意

  1. 将原问题划分成其子问题,注意:子问题必须要与原问题的解法相同
  2. 递归出口(即是结束递归条件)

斐波那契数列

斐波那契数列就是 1,1, 2,3,5,8,13…
第一二项都是1,接下来每一项都等于前两项之和
函数求出斐波那契数列第n项,是比较经典的递归题目练习;
斐波那契数列第n项 fib(n)=fib(n-1)+fib(n-2)
求出第五项斐波那契数就是5
在这里插入图片描述
代码如下

public static int fib(int n) { if (n == 1 || n == 2) { return 1; }return fib(n - 1) + fib(n - 2); }

当我们求 fib(36) 的时候发现, 程序执行速度极慢. 原因是进行了大量的重复运算,如上图所示
因此可以使用循环的方式来求斐波那契数列问题, 避免出现冗余运算.
如下代码,此时程序的执行效率大大提高了.

public static int fib(int n) { int last2 = 1; int last1 = 1; int cur = 0; for (int i = 3; i <= n; i++) { cur = last1 + last2; last2 = last1; last1 = cur; }return cur; }