javaSE- 方法的使用
创始人
2024-02-25 16:16:04
0

一、方法的基本用法

方法就是一个代码片段. 类似于 C 语言中的 “函数”.
方法存在的意义(不要背, 重在体会):

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

回忆一个之前写过的代码: 计算 1! + 2! + 3! + 4! + 5!

public static void main(String[] args) {int sum = 0;for (int i = 1; i <= 5; i++) {int tmp = 1;for (int j = 1; j <= i; j++) {tmp *= j;}sum += tmp;}System.out.println("sum = " + sum);}

这个代码中使用双重循环, 比较容易写错.
接下来我们可以使用方法来优化这个代码

	/*** 计算 n 阶乘* @param n* @return*/public static int tmp(int n){int ret = 1;for(int i = 1; i <= n; i++){ret = ret * i;}return ret;}public static void main(String[] args) {int sum = 0;for (int i = 1; i <= 5; i++) {//产生 1 - 5的数int ret = tmp(i);//tmp 这个函数就是 计算 n 阶乘sum = sum + ret;}System.out.println("sum = " + sum);}

在这里插入图片描述

像上面tmp函数的功能就是计算一个数的阶乘,这就是函数的基本用法,并且这个函数的功能是唯一的

1.1、方法定义语法

// 方法定义
public static 方法返回值 方法名称([参数类型 形参 ...]){方法体代码;[return 返回值];
}

在这里插入图片描述

1.1.1、代码示例: 实现一个方法实现两个整数相加

	public static int sumAdd(int x, int y){return x + y;}public static void main(String[] args) {int a = 10;int b = 20;int sum = sumAdd(a, b);System.out.println("sum = " + sum);}

在这里插入图片描述

方法的参数叫做形参,main方法的参数叫实参,形参相当于实参的一份拷贝,这种传参方式被称为 按值传递(传值)
由此引申出一个知识点, 在Java中 是没有 传址 的概念,只有传值,所以我们在调用方法的时候,只需要注重 形参 和 实参 的类型 和 个数 是否匹配(相同)
在这里插入图片描述

1.1.2、既然讲到函数(方法),也就会涉及函数栈帧问题

想了解 c方面的或者想对比一下的,可以看这篇文章函数栈帧销毁与创建(vs2013)- 修改版
在这里插入图片描述

1.1.3、注意事项

  1. public 和 static 两个关键字在此处具有特定含义, 我们暂时不讨论, 后面会详细介绍.
  2. 方法定义时, 参数可以没有. 每个参数要指定类型
  3. 方法定义时, 返回值也可以没有, 如果没有返回值, 则返回值类型应写成 void
  4. 方法定义时的参数称为 “形参”, 方法调用时的参数称为 “实参”.
  5. 方法的定义必须在类之中, 代码书写在调用位置的上方或者下方均可.
  6. Java 中没有 “函数声明” 这样的概念

1.1.4、方法调用的执行过程

基本规则

定义方法的时候, 不会执行方法的代码. 只有调用的时候才会执行.
当方法被调用的时候, 会将实参赋值给形参.
参数传递完毕后,就会执行到方法体代码.
当方法执行完毕之后(遇到 return 语句), 就执行完毕, 回到方法调用位置继续往下执行
一个方法可以被多次调用.

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

public static void main(String[] args) {int a = 10;int b = 20;System.out.println("交换前:" + "a = " + a + " b = " + b);swap(a, b);System.out.println("交换前:" + "a = " + a + " b = " + b);}public static void swap(int x, int y) {int tmp = x;x = y;y = tmp;}

在这里插入图片描述
原因分析:
刚才的代码, 没有完成数据的交换.
对于基础类型来说, 形参相当于实参的拷贝. 即 传值调用
可以看到, 对 x 和 y 的修改, 不影响 a 和 b
解决办法: 传引用类型参数 (例如数组来解决这个问题),这个数组 的 时候在讲。

1.2、没有返回值的方法

就像上面的swap函数,是没有返回值的

//有两种形式:public static void swap(int x, int y) {int tmp = x;x = y;y = tmp;}public static void fun(int c){return;}

在这里插入图片描述

1.3、方法的重载overlord(重点)

有些时候我们需要用一个函数同时兼容多种参数的情况, 我们就可以使用到方法重载

错误的例子

	public static void main(String[] args) {int a = 10;int b = 20;int ret = add(a, b);System.out.println("ret = " + ret);double a2 = 12.5;double b2 = 18.5;double ret2 = add(a2, b2);//图 13System.out.println("ret2 = " + ret2);}public  static  int add(int x,int y){return  x+y;}

在这里插入图片描述
由于参数类型不匹配, 所以不能直接使用现有的 add 方法

那么是不是应该创建这样的代码呢?

public static void main(String[] args) {int a = 10;int b = 20;int ret = addInt(a, b);System.out.println("ret = " + ret);double a2 = 10.5;double b2 = 20.5;double ret2 = addDouble(a2, b2);System.out.println("ret2 = " + ret2);}public static int addInt(int x, int y) {return x + y;}public static double addDouble(double x, double y) {return x + y;}

如果要计算float类型,那是不是要写一个addFloat函数,那这样不就很麻烦吗
所以就要使用方法的重载

1.3.1、使用重载

	public static void main(String[] args) {int a = 10;int b = 20;int ret = add(a, b);System.out.println("ret = " + ret);double a2 = 10.5;double b2 = 20.5;double ret2 = add(a2, b2);System.out.println("ret2 = " + ret2);double a3 = 10.5;double b3 = 10.5;double c3 = 20.5;double ret3 = add(a3, b3, c3);System.out.println("ret3 = " + ret3);}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;}

在这里插入图片描述

方法的名字都叫 add. 但是有的 add 是计算 int 相加, 有的是 double 相加; 有的计算两个数字相加,
有的是计算三个数字相加. 同一个方法名字, 提供不同版本的实现, 称为 方法重载

1.3.2、重载的规则

参考JavaSE的标准文档
可以不是用一个类,继承关系也是可以的

  • 方法名相同
  • 方法的参数不同(参数个数或者参数类型)
  • 方法的返回值类型不影响重载
    在这里插入图片描述

1.4、方法递归

1.4.1、递归的概念

一个方法在执行过程中调用自身, 就称为 “递归”.
递归相当于数学上的 “数学归纳法”, 有一个起始条件, 然后有一个递推公式
递推公式是递归的重点,推出它,递归就很好写。

使用递归之前,需要一个前提
  1. 有一个趋近于终止的条件(停止递归的条件)
  2. 自己调用自己
public static void main(String[] args) {func();}这样写,就不满足 使用递归所需的第一个条件 没有一个终止递归的条件所以该程序会无限递归死循环,最终导致栈溢出(栈空间不是无限大,是有限,func方法一直调用自己下去,最终肯定是会 爆满/溢出 的)因为 每次调用 func方法时,都会为其在栈上空间开辟块自己的空间public  static void func(){func();}

在这里插入图片描述

那我该怎么去写一个可以使用的递归呢?

1. 有一个趋近于终止的条件(停止递归的条件)
2. 自己调用自己

代码示例: 递归求 N 的阶乘

	public static void main(String[] args) {//递归求 N 的阶乘int n = 5;int ret = fun(n);System.out.println(ret);}public static int fun(int n){if(n == 1){return 1;}return n * fun(n-1);}1! == 1 //这就是我们的起始条件,也是我们的终止条件2! == 2*1 == 2 * 1!3! == 3*2*1 == 3 * 2!4! == 4*3*2*1 == 4 * 3!5! == 5*4*3*2*1 == 5 * 4!你发现了 求 5!的值,它是 5 * (5-1)!而  4! == 4 * (4-1)!3!  == 3 * (3-1)!2!  == 2 * (2-1)!5! == 5 * 4!== 5 * 4 * 3! == 5 * 4 * 3 * 2! == 5 * 3 * 2 * 1程序运行 跟我们刚才藏宝殿是一样的,一层一层的抢。从最里面的开始抢也就从我们终止条件开始n == 1;  return 1;// 这里的返回值 是返回到 调用它的上一层级(藏宝殿核心是第一层吗,抢完了,肯定去抢第二程啊)n == 2   return 2* factorial(2-1) == 2 * 1 == 2n == 3;  return 3 * 2 == 6n == 4;  return 4 * 6 == 24n == 5;  return 5 *   ==考验你们的时候,在下面评论,看你们到底有没有看懂学会递归的字面意思递归 n * factorial(n-1)l  n-1 就是它传过去的值,称为递, factorial(n-1)返回的值,称为归结合称为: 递归。

在这里插入图片描述

执行过程
![public static void main(String[] args) {//递归求 N 的阶乘int n = 5;int ret = fun(n);System.out.println(ret);}public static int fun(int n){if(n == 1){return 1;}return n * fun(n-1);}

在这里插入图片描述

关于 “调用栈”
方法调用的时候, 会有一个 “栈” 这样的内存空间描述当前的调用关系. 称为调用栈.
每一次的方法调用就称为一个 “栈帧”, 每个栈帧中包含了这次调用的参数是哪些, 返回到哪里继续执行等信息.
后面我们借助 IDEA 很容易看到调用栈的内容

1.4.2、 递归练习

代码示例1 按顺序打印一个数字的每一位(例如 1234 打印出 1 2 3 4)

public static void main(String[] args) {//按顺序打印一个数字的每一位(例如 1234 打印出 1 2 3 4)int n = 4569;print(n);}public static void print(int n){if(n > 9){print(n / 10);}System.out.println(n % 10);}

在这里插入图片描述

代码示例2 递归求 1 + 2 + 3 + … + 10

public static void main(String[] args) {//递归求 1 + 2 + 3 + ... + 10int a = 10;int ret = sumAdd(a);System.out.println(ret);}public static int sumAdd(int n){if(n == 1){return 1;}return n + sumAdd(n - 1);}

代码示例3 写一个递归方法,输入一个非负整数,返回组成它的数字之和. 例如,输入 1729, 则应该返回1+7+2+9,它的和是19

public static void main(String[] args) {//代码示例3 写一个递归方法,输入一个非负整数,返回组成它的数字之和.// 例如,输入 1729, 则应该返回1+7+2+9,它的和是19int a = 1729;int ret = printAdd(a);System.out.println(ret);}public static int printAdd(int num){if(num <= 9){return num;}return num % 10 + printAdd(num / 10);}

代码示例4 求斐波那契数列的第 N 项

斐波那契数列介绍
斐波那契数列:1,1,2,3,5,8,13,21,34,55,89…

public static void main(String[] args) {///代码示例4 求斐波那契数列的第 N 项//斐波那契数列:1,1,2,3,5,8,13,21,34,55,89...int n = 10;int ret = fibonacci(n);System.out.println(ret);}public static int fibonacci(int n){if(n == 1 || n == 2){return 1;}return fibonacci(n - 1) + fibonacci(n - 2);}

用 递归的方法来求 斐波那契数,效率很低

当我们求 fibonacci(40) 的时候发现, 程序执行速度极慢. 原因是进行了大量的重复运算

public static int cont = 0;public static void main(String[] args) {///代码示例4 求斐波那契数列的第 N 项//斐波那契数列:1,1,2,3,5,8,13,21,34,55,89...int n = 40;int ret = fibonacci(n);System.out.println(ret);System.out.println("函数执行了:" + cont + "次");}public static int fibonacci(int n){if(n == 1 || n == 2){return 1;}if(n == 3){cont++;}return fibonacci(n - 1) + fibonacci(n - 2);}

在这里插入图片描述
在这里插入图片描述
可以使用迭代/循环的方式来求斐波那契数列问题, 避免出现冗余运算

    public static int cont = 0;public static int fibonacci(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;cont++;}System.out.println("函数执行了:" + cont + "次");return cur;}public static void main(String[] args) {///代码示例4 求斐波那契数列的第 N 项//斐波那契数列:1,1,2,3,5,8,13,21,34,55,89...int n = 40;int ret = fibonacci(n);System.out.println(ret);}

在这里插入图片描述

递归小结

递归是一种重要的编程解决问题的方式.
有些问题天然就是使用递归方式定义的(例如斐波那契数列, 二叉树等), 此时使用递归来解就很容易.
有些问题使用递归和使用非递归(循环)都可以解决. 那么此时更推荐使用循环, 相比于递归, 非递归程序更加高效

相关内容

热门资讯

朝阳发布智能机器人“政策包+场... 12月19日,首届朝阳智能机器人生态大会暨Robo Summit机器人发展论坛(第二期)在国家速滑馆...
解金融之困 传调解之暖——“总... 小微企业贷款逾期,如何既保债权又留生机? 三车连撞纠纷棘手,怎样快速厘清责任? 金融消费遇“低息陷阱...
问法预告|12月23日半岛问法... 养老继承是社会生活中谁也绕不开的话题,当面临这一问题时家庭成员之间难免会发生一些矛盾。当问题真正来临...
原创 泰... 这座桥在中国企业的支持下,刚通车不久,却因为一场突如其来的空袭被炸成废墟,显然这场冲突的复杂程度远远...
原创 为... 中国古代的社会经济主要依赖自给自足的小农经济,生产力发展相对滞后,但战争却始终贯穿着王朝的历史。从某...
一起普通师生纠纷,牵动全县多个... 今年9月底,一起因拉人进群而被跨省传唤的事件,登上新闻热搜。 澎湃新闻近日调查发现,该事件背后,是一...
如何在刑事律师推荐榜中选到合适... 刑事律师的重要性在法律领域,刑事律师扮演着关键角色。 当个人或企业面临刑事案件时,专业刑事律师能提供...
刑事律师排名怎么选到合适律师? 刑事律师排名的意义刑事律师排名在一定程度上能反映律师的专业能力、经验和业界认可度。 对于面临刑事案件...
制度深耕 丰景如峰 大豆收获作业。庞遵明摄 □本报记者 姜斌 刘畅 银装素裹的北大荒,是一卷由冰雪、沃土与数据共同谱写的...
每经热评|告慰小洛熙,唯有权威... 每经评论员 付克友 宁波5月龄女婴“小洛熙”在医院接受心脏手术后不幸离世,连日来引发舆论关注。一个尚...