目录
4.样式举例计算 1! + 2! + 3! + 4! + 5!
程序逻辑控制
我们每次去银行的ATM机上取钱的时候,第一个步骤是不是都需要把银行卡插入ATM机中的卡槽中,而且银行卡还分正反面进入ATM机,当通过ATM机的验证后,才能进入ATM机的系统中,在系统中经过一系列的逻辑验证最终才能取到money。大家有没有想过这些操作的顺序和验证的逻辑是怎么实现的?我们今天就来学习实现这些逻辑的内部结构。
一.顺序结构
在解数学题的时候 ,是不是需要一步一步的解出来,我们顺序结构就是这样,在执行某个程序的时候,我们一步一步的执行。
public static void main(String[] args) {
System.out.println("aaa");
System.out.println("bbbb");
System.out.println("cccccc");
}
二.分支结构
什么条件下需要分支结构?当我们在取钱的时候,是不是需要输入密码!在输入密码的时候输入正确,是不是需要继续执行正确的操作。当输入密码错误的时候,是不是也要执行相对应解决问题的代码。不可能输入正确 和输入错误都是执行相同的操作结果叭!!这种时候我们就需要用到分支结构。
1.if语句
if语句语法格式
在分支结构中我们用if关键字实现分支语句,并且实现语句的格式一般有三种
语法格式1
if(布尔表达式){
// 语句
}
布尔表达式的结果为true时才会继续执行if中的语句,否则不在执行if语句
语法格式2
if(布尔表达式){
// 语句1
}else{
// 语句2
}
像这种情况布尔表达式为false时就会执行else中的语句
语法格式3
if(布尔表达式1){
// 语句1
}else if(布尔表达式2){
// 语句2
}else{
// 语句3
}
布尔表达式1中为true执行第一个if的语句,否则进入第二个布尔表达式进行判断,当第二个为true执行第二个,若前两个布尔表达式都是false则直接直接最后一个else中的语句3.
2.if语句中的书写格式
1.风格1
int x = 10;
if (x == 10) {
// 语句1
} else {
// 语句2
}
2.风格2
int x = 10;
if (x == 10)
{
// 语句1
}
else
{
// 语句2
}
两种格式都是合法的,在Java中更推荐使用风格1.
3.if语句出现的问题
分号问题
int x = 20;
if (x == 10);
{
System.out.println("hehe");
}
上面的if语句后面出现了分号,这就导致了if语句和后面用{}括起来的的代码没有构成分支结构关系,而是成立了一个独立的语句体。
悬垂else问题
int x = 10;
int y = 10;
if (x == 10)
if (y == 10)
System.out.println("aaa");
else
System.out.println("bbb");
我们观察代码会发现在我们的第一个if语句中还嵌套着另一个if语句,在另一个if语句的后面还有一个else语句,但不同的时,这个else语句从格式结构来看是与第一个if语句相匹配的,但是在执行结果的时候,当我们的第二个if语句中的boolean类型为false我们的程序此时会执行与if匹配最接近的else,这就是悬垂else问题。这样的if/ else 语句中可以不加 大括号 . 也可以写语句(只能写一条语句). 但是不建议这样写。
2.switch语句
switch语在Java中,通过比较表达式的值与每个case语句中的常量值来确定执行哪个代码块。如果表达式的值与某个case语句中的常量值匹配,则执行该case语句后的代码块,并通常在执行完毕后通过break语句跳出switch语句。如果表达式的值与所有case语句中的常量值都不匹配,那么会执行default语句块中的代码(如果存在的话)。
1.switch基本语法
switch(表达式){
case 常量值1:{
语句1;
[break;]
}
case 常量值2:{
语句2;
[break;]
}
...
default:{
内容都不满足时执行语句;
[break;]
}
}
2.使用switch语句的注意事项
1.多个case后的常量值不可以重复
2.switch的括号内只能是以下类型的表达式:
基本类型:byte、char、short、int,注意不能是long类型,引用类型:String常量串、枚举类型
3.break 不要遗漏, 否则会失去 "多分支选择" 的效果
4.switch 不能表达复杂的条件
5.switch 虽然支持嵌套, 但是很丑,一般不推荐~
3.switch样式举例
int day = 1;
switch(day) {
case 1:
System.out.println("星期一");
break;
case 2:
System.out.println("星期二");
break;
case 3:
System.out.println("星期三");
break;
case 4:
System.out.println("星期四");
break;
case 5:
System.out.println("星期五");
break;
case 6:
System.out.println("星期六");
break;
case 7:
System.out.println("星期日");
break;
default:
System.out.println("输入有误");
break;
}
三.循环结构
我们在学习循环结构之前先学习两个关键字,分别是break关键字和continue关键字
break:跳出本语句块或跳出循环结构执行循环以外的代码
continue:常用于循环结构中,功能为跳过本次循环执行下一次循环
什么情况下我们需要循环,从1加到10的时候?我们该如何办?在没有学循环结构的时候,我们一般想到的是书写10条这样的加法语句,那要是加到1000呢?是不是要写一千条这样的语句,这个时候我们就要借助循环来解决这类问题。
1.while循环
1.基本语法格式
while(循环条件){
循环语句;
}
循环条件为 true, 则执行循环语句; 否则结束循环.
2.while循环执行流程
1.初始化
在while循环开始之前,程序会执行任何在循环之前的初始化代码。这可以包括变量的声明和初始化,或者其他必要的设置。
2.检查条件
程序会计算while循环后的条件表达式。这个条件表达式必须返回一个布尔值(true或false)。
3.执行循环体
如果条件表达式的值为true,程序将执行循环体内的代码块。循环体是花括号{}内的代码,它们定义了循环应该重复执行的操作。
4.再次检查条件
一旦循环体执行完毕,程序将再次回到第2步,重新计算条件表达式的值。
5.重复或退出
如果条件表达式的值仍为true,程序将再次执行循环体。这个过程会一直重复,直到条件表达式的值变为false。一旦条件变为false,程序将跳过循环体,并继续执行while循环之后的代码。
6.继续后续代码
当while循环的条件不再满足时,程序将退出循环,并继续执行紧跟在while循环之后的代码。
这个流程会一直持续,直到条件不再满足为止。如果条件永远不满足(即死循环),则程序将无限期地继续执行循环体,直到被外部因素(如用户中断、系统错误等)停止。
3.while循环容易出现的问题
1.死循环:
如果while循环的条件始终为真,或者循环体内没有改变条件的操作,那么循环就会无限进行下去,形成死循环。这可能会消耗大量的计算资源,甚至导致程序崩溃。
在某些情况下,即使循环条件在逻辑上应该能够变为假,但由于编程错误(如变量更新错误),也可能导致死循环。
2.循环体执行不完整或错误
如果循环体内的代码没有按照预期执行,或者由于某些原因(如异常或提前退出)而中断,那么循环可能无法完成其任务。
循环体中的操作可能出错,导致数据被错误地修改或处理。
3.循环次数过多或过少:
如果循环条件设置不当,可能导致循环执行的次数比预期的多或少,这会影响程序的正确性和性能。
4.未初始化的变量:
在进入while循环之前,如果循环条件中使用的变量没有被正确初始化,那么循环可能不会按照预期执行。
5.嵌套循环问题:
当使用嵌套while循环时,如果内层循环的条件或操作不正确,可能会影响外层循环的执行。此外,过深的嵌套循环可能导致代码难以理解和维护,并可能影响程序的性能。
6.代码可读性和可维护性问题:
复杂的while循环结构可能导致代码难以阅读和理解,增加维护和调试的难度。
4.使用while循环注意事项
1.while 下面的语句可以不写 { } , 但是不写的时候只能支持一条语句. 建议还是加上 { }
2.while 后面的 { 建议和 while 写在同一行.
3.while 后面不要多写 分号, 否则可能导致循环不能正确执行.
5.样式案例
int num = 100;
while (num <= 200) {
if (num % 3 == 0) {
System.out.println("找到了 3 的倍数, 为:" + num);
break;
}
num++;
}
// 执行结果
找到了 3 的倍数, 为:102
2.for循环
1.语法格式
for(表达式①;布尔表达式②;表达式③){
表达式④;
}
表达式1: 用于初始化循环变量初始值设置,在循环最开始时执行,且只执行一次
表达式2: 循环条件,满则循环继续,否则循环结束
表达式3: 循环变量更新方式
2.执行流程
①②③④--->②③④--->②③④--->②③④--->②③④--->②③④--->...--->②为false,循环结束
3.注意事项出现问题
跟while循环类似不在讲述
4.样式举例计算 1! + 2! + 3! + 4! + 5!
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);m.out.println("sum = " + sum);
3.do..while循环(不建议使用)
1.基本语法格式
do{
循环语句;
}while(循环条件);
2.执行流程:
先执行循环语句, 再判定循环条件,循环条件成立则继续执行,否则循环结束
3.样式举例打印 1 - 10
int num = 1;
do {
System.out.println(num);
num++;
} while (num
4.注意事项
1.do while 循环最后的分号不要忘记
2. 一般 do while 很少用到, 更推荐使用 for 和 while.
四.输入输出
1.控制台输出
基本语法:
System.out.println(msg); // 输出一个字符串, 带换行
System.out.print(msg); // 输出一个字符串, 不带换行
System.out.printf(format, msg); // 格式化输出
注意事项:
1.println 输出的内容自带 \n, print 不带 \n
2.printf 的格式化输出方式和 C 语言的 printf 是基本一致的.
代码演示
System.out.println("hello world");
int x = 10;
System.out.printf("x = %d\n", x)
格式化字符串
转换符 | 类型 | 举例 | |
d | 十进制整数 | ("%d", 100) | 100 |
x | 十六进制整数 | ("%x", 100) | 64 |
o | 八进制整数 | ("%o", 100) | 144 |
f | 定点浮点数 | ("%f", 100f) | 100.000000 |
e | 指数浮点数 | ("%e", 100f) | 1.000000e+02 |
g | 通用浮点数 | ("%g", 100f) | 100.000 |
a | 十六进制浮点数 | ("%a", 100) | 0x1.9p6 |
s | 字符串 | ("%s", 100) | 100 |
c | 字符 | ("%c", ‘1’) | 1 |
b | 布尔值 | ("%b", 100) | true |
h | 散列码 | ("%h", 100) | 64 |
% | 百分号 | ("%.2f%%", 2/7f) | 0.29% |
2.键盘输入
在Java中的键盘输入我们需要借助Scanner读取字符串/整数/浮点,在使用Scanner时我们还需要导入import java.util.Scanner; 包。样式代码
import java.util.Scanner; // 需要导入 util 包
Scanner sc = new Scanner(System.in);
System.out.println("请输入你的姓名:");
String name = sc.nextLine();
System.out.println("请输入你的年龄:");
int age = sc.nextInt();
System.out.println("请输入你的工资:");
float salary = sc.nextFloat();
System.out.println("你的信息如下:");
System.out.println("姓名: "+name+"\n"+"年龄:"+age+"\n"+"工资:"+salary);
sc.close(); // 注意, 要记得调用关闭方法
// 执行结果
请输入你的姓名:
张三
请输入你的年龄:
18
请输入你的工资:
1000
你的信息如下:
姓名: 张三
年龄:18
工资:1000.0
使用输入操作时注意事项
1.格式错误
用户输入的格式可能不符合程序的要求。例如,如果程序期望一个整数,但用户输入了一个字符串或小数,就会导致输入错误。
2.非法字符
用户可能输入了程序无法处理的特殊字符或非法字符。这些字符可能会导致程序崩溃或产生不可预测的行为。
3.大小写敏感
某些输入可能是大小写敏感的,但用户可能没有注意到这一点。例如,密码或用户名通常区分大小写,如果用户输入了错误的大小写组合,就会导致验证失败。
4.多余或缺少空格
用户输入中可能包含多余的空格或缺少必要的空格,这可能导致解析错误或逻辑错误。
5.非预期输入
用户可能输入了程序没有预料到的内容,比如程序期望一个选择项(如“yes”或“no”),但用户输入了其他内容。
6.输入不完整
用户可能只输入了部分所需信息就提交了,导致程序无法正常工作。
方法的使用
五.方法的概念
1.认识方法
什么是方法?方法有什么作用,在Java中有什么意义?
大家在刚上大学的时候,有没有这样的困扰!!每个宿舍的卫生间的淋浴装置都是需要一个app进行启动的,因为咱们是第一次上这个大学,不知道如何操作。这个时候我们就会去询问辅导员,我们要洗澡,我们该怎么办?需要下载那个app?由于我们询问的人数众多,辅导员忙得不可开交,同时辅导员也发现学生问的都是同样的问题!这个时候导员会在群里面发布一则公告,公告中就记录着如何解决洗澡问题!大家有没有发现,在这个洗澡问题中,导员本来是应该一个一个学生的回复的,但是导员通过群公告这个功能就解决了重复性回答学生的问题。
在Java中我们需要对某段代码块进行反复的调用,每调用一次就要书写一次,反复的书写就会使我们的代码中出现很多相同的代码,为了避免代码冗余问题?我们有没有一种功能可以对这些需要反复调用的代码进行保存在一起,需要的时候调用这个功能就行?方法,方法就能解决这一问题。那方法是个什么东西呢!Java中的方法就跟C语言的函数功能一样,它是对某个需要实现的功能的一种描述,把实现这个功能的代码集合在一起,组建成一个具有特有功能的代码片段,能够让代码在不同的位置反复的调用。方法出现的意义也是解决了大量重复代码的生成,使规模复杂的代码片段能够模块化组织代码,让代码可读性,可用性更强了。
我们不仅仅需要认识方法,还需要会使用方法,下面我们就来了解了解方法的使用叭。
2.方法的语法格式
// 方法定义
修饰符 返回值类型 方法名称([参数类型 形参 ...]){
方法体代码;
[return 返回值];
}
修饰符:它是方法其中的一种固定搭配现阶段使用public static(在封装中会详解修饰符)
返回值类型:这个就跟我们数据类型,引用类型有关,比如:我们调用的这个方法是实现一个加法的代码功能,那么在这个方法中进行加法计算的时候就会生成加法结果,加法结果一般是int类型的,在main方法中我们调用这个功能肯定希望它返回一个结果,当这个方法需要返回一个结果的时候,我们就需要根据这个结果类型,在方法上定义一个相同的值类型。如果没有返回值,请使用void修饰此方法。
方法名称:方法的名字需要通俗易懂,一般使用小驼峰命名
参数类型:这个也跟数据类型和引用类型有关!还是调用加法举例,我们调用加法去计算两个变量或者常量(这个地方统一用变量举例),是不是需要把这两个变量传递给调用的方法,方法获得了数据是不是才能进行计算,而参数类型就是根据我们传递的这个变量的类型设置的,比如:传递10 它的类型就是int,在方法中我们就需要用到int参数类型来接收
形参:传值的时候我们方法知道了你要传值的类型参数,但是没有一个内存来接收我们传递的这个数据,这个时候形参就是来接收这个传递的数据的
方法体:实现代码功能的一个片段。对加法操作进行代码实现的一块语句
return[返回值]:加法执行完后,就需要把结果给返回到调用的函数中,此时的return 就肩负着返回结果的功能
样式代码举例
public static int Add(int a,int b){
int count = 0;
count = a + b;
return count;
}
public static void main(String[] args) {
int a = 10;
int b = 20;
int count = Add(a,b);
System.out.println(count);
}
//执行结果
30
我们看上面的代码可能会发现,main方法中传递的变量和接收返回的结果的变量和方法中的名字是一模一样的!那他们是不是同一个变量呢?首先我肯定的回答你不是的,这是两个不同的变量,只是变量名相同。所以,我建议初学者在定义方法中的变量名和main中的变量名时尽量不要定义成相同的变量名,否则容易混淆。
在了解到方法的格式后,是不是有种迫不及待的心情想上手敲敲代码,我知道你急,但你先别急。方法也是分类型的,有些方法需要返回值,有些不需要等等,在真正动手写代码之前,我们还得认识一下我们方法有哪几种类型。
3.方法的类型
1.无参无返回值的方法
public static void func1(){
System.out.println("我是一个无参数无返回值的方法");
}
public static void main(String[] args) {
//无参无返回值
func1();
}
//执行结果
我是一个无参数无返回值的方法
2.有参数无返回值的方法
public static void func2(int age){
System.out.println("我是一个无返回值,但有参数的方法");
}
public static void main(String[] args) {
//无返回值有参
func2(2);
}
//执行结果
我是一个无返回值,但有参数的方法
3.有返回值无参数的方法
public static boolean func3(){
int x = 0;
if(x == 0){
System.out.println("我是一个有返回值类型,但没有参数的方法");
return true;
}
return false;
}
public static void main(String[] args) {
func3();
}
//执行结果
我是一个有返回值类型,但没有参数的方法
4.有返回值有参数的方法
public static boolean func4(int age){
age = 0;
if(age == 0){
System.out.println("我是一个有返回值类型也有参数的方法");
return true;
}
return false;
}
public static void main(String[] args) {
//有返回值有参
func4(2);
}
//执行结果
我是一个有返回值类型也有参数的方法
4.方法的执行过程
方法调用过程
调用方法--->传递参数--->找到方法地址--->执行被调方法的方法体--->被调方法结束返回--->回到主调方法继续往下执行
我们通过代码演示
public static int add(int x, int y){
System.out.println("正在调用方法");
return x + y;
}
public static void main(String[] args) {
int a = 10;
int b = 20;
System.out.println("方法调用之前:");
//接收数据
int ret = add(a,b);
System.out.println("调用方法之后a+b:" + ret);
}
方法执行过程
5.代码演示
计算 1! + 2! + 3! + 4! + 5!
public static int fac(int n){
int count = 0;
int result = 1;
for(int i = 1; i <= n; i++){
result = 1;
for(int j = 1; j <= i; j++){
result *= j;
}
count += result;
}
return count;
}
public static void main(String[] args) {
int sum = 0;
sum = fac(5);
System.out.println("1!+2!+3!+4!+5!="+sum);
}
//执行结果
153
6.形参实参的理解(重点)
形参:用于定义函数/方法,接收实参,不需要有确定的值。
实参:用于传递给函数/方法的参数,必须有确定的值。
在方法定义中会有参数类型和形参名 形参就是来接收实参传递给方法中的值的,为什么要理解这个形参实参了,咱们看下面这段代码
public static void swap(int x,int y){
int tmp = x;
x = y;
y = tmp;
System.out.println("swap方法中:" + "x:" + x + "y:" + y);
}
public static void main(String[] args) {
int a = 10;
int b = 20;
System.out.println("调用swap之前:" + "a:" + a + "b:" + b);
swap(a,b);
System.out.println("调用swap之后:" + "a:" + a + "b:" + b);
}
根据结果,我们发现形参在接收到实参之后,形参中的数据进行交互得到的结果为20,10.然而实参中的结果没有变动,跟调用swap之前一样。这是为什么呢?是因为实参a和b是main方法中的两个变量,其空间在main方法的栈(一块特殊的内存空间)中,而形参x和y是swap方法中的两个变量,x和y的空间在swap方法运行时的栈中,因此:实参a和b 与 形参x和y是两个没有任何关联性的变量,在swap方法调用时,只是将实参a和b中的值拷贝了一份传递给了形参x和y,因此对形参x和y操作不会对实参a和b产生任何影响。
如果我要实现形参内容的改变能影响实参内容的改变该如何做呢?
public static void swap(int[] arr){
int tmp = arr[0];
arr[0] = arr[1];
arr[1] = tmp;
}
public static void main(String[] args) {
int[] arr = {10,20};
System.out.println("swap调用前:" + "arr[0]:" + arr[0] + " arr[1]:" + arr[1]);
swap(arr);
System.out.println("swap调用后:" + "arr[0]:" + arr[0] + " arr[1]:" + arr[1]);
}
当我们通过引用类型传递数据,就能改变我们实参中的内容。但是在我们Java中是没有引用类型传递的。只有值传递。那为什么我上面的代码是通过引用传递实现的了?在上一段代码实现的过程中实参传形参传的内容是确定的值,这个地方传的其实也是值,不过这个值是实参数据的地址,所以我们在改变形参时实参也会发生改变。
实参形参总结
1.在Java中,实参的值永远都是拷贝到形参中,形参和实参本质是两个实体
2.对于基础类型来说, 形参相当于实参的拷贝. 即 传值调用
3.Java中只有值传递
7.方法重载
1.方法重载概念
你是个好人,你是个好人,你是个好人!我相信大家在生活中听到过这句话。这句话在不同的语境下表达的意思也是不一样的,有着一语双关的用意。重载就是这样,我们方法外壳都相同,只是表达的意思不同,那为什么需要重载呢?
2.为什么需要重载
我们看代码
public static int add(int a,int b){
return a+b;
}
public static void main(String[] args) {
int x = 10;
int y = 20;
add(x,y);
int ret = add(x,y);
System.out.println(ret);
double a1 = 1.0;
double a2 = 20.2;
//程序编译报错 为什么类型不匹配,可能会有数据精度丢失
double d = add(a1,a2);
System.out.println(d);
}
}
像这样一段代码如果是浮点型的数据类型想要使用加法功能,但是加法功能是int类型的,能不能使用呢?其实能使用的,为什么我的代码中报错了。因为在使用过程中我们double类型的数据精度会丢失,会导致我们得到的数据不准确,所以就出现编译报错。有没有什么办法能够解决这一问题了!有的,重新写一个方法就行。
public static double addDouble(double a,double b){
return a+b;
}
的确重新写一个新方法就能解决这个问题,如果有一百个这样类型的操作那我们是不是重新写一百个像这样不同名字的方法,导致代码中存在大量功能相似但名称不同的方法,增加了代码的冗余性和维护成本。为了解决这一问题,Java就推出了方法重载的概念,使得方法与方法之间增加了多态性,不仅简化了代码,还提高了代码的重用性和扩展性。其实在我们Java中还有一个重写功能,这个重写功能又有什么作用了?(继承和多态当中详讲)。
3.实现方法重载需要注意的事项
1.重载的方法名是必须相同的
2.参数列表是必须相同,以及参数列表中的参数个数,参数类型,类型次序不能相同
3.返回值类型的改变不会影响方法重载
4.方法重载的应用举例
public class Calculator {
// 方法重载:整数加法
public int add(int a, int b) {
return a + b;
}
// 方法重载:浮点数加法
public double add(double a, double b) {
return a + b;
}
// 方法重载:三个整数加法
public int add(int a, int b, int c) {
return a + b + c;
}
public static void main(String[] args) {
Calculator calculator = new Calculator();
// 调用整数加法
int sumInt = calculator.add(5, 3);
System.out.println("整数相加的结果: " + sumInt);
// 调用浮点数加法
double sumDouble = calculator.add(5.5, 3.3);
System.out.println("浮点数相加的结果: " + sumDouble);
// 调用三个整数加法
int sumThreeInt = calculator.add(5, 3, 2);
System.out.println("三个整数相加的结果: " + sumThreeInt);
}
}
5.对方法签名的理解
方法签名在计算机编程中是一个核心概念,它指的是方法的声明部分,主要包括方法的名称、参数列表和返回类型。方法签名是用来标识和区分不同方法的关键信息,它决定了方法的唯一性。
具体来说,方法名用于唯一标识该方法,并在程序的声明部分中给出,用于调用该方法。参数列表则是一组用逗号分隔的参数,定义了方法接受的输入,其中包含参数的数据类型和参数的名称。返回类型则定义了方法执行后返回的值的数据类型;如果方法不返回任何值,可以使用void关键字表示。并且它也是模块在软件程序中如何工作的定义,可以被视为模块的使用者和生产者之间的正式合同。在Java等编程语言中,同一个类中不能有两个方法具有相同的签名,即使它们的返回类型不同。但是,方法的重载允许在同一个类中定义多个方法名相同但参数列表不同的方法,从而根据参数的数量或类型来区分它们。我们需要注意的是,尽管参数的数据类型和名称以及方法的返回类型都与方法的声明有关,但方法的签名中并不包含参数的具体名称和返回类型。这是因为方法签名的主要目的是用于标识和区分不同的方法,而参数名称和具体的返回类型在实现上可能会有所不同,但不影响方法的唯一性。
总的来说,方法签名是理解和使用编程中方法的关键,它确保了方法的唯一性,使得编译器和开发者能够准确地识别和执行特定的方法。
8.递归(简述)
个人理解递归的出现往往都是为了解决复杂中的重复性问题,什么意思呢!比如我有一个问题A需要解决,但是解决问题A的之前还需要解决掉问题A内部的问题B,此时问题B中也有一个问题C需要解决,他们有一个共性就是解决问题的办法都是相同的,只不过是需要我们一层一层的去解决。而递归的出现就是为了解决这一样问题。(在理解递归这件事上我们可以想想盖房子的步骤)。
在实现递归的过程中,每次调用函数,我们问题规模应该是不断减小的一个状态,最后达到退出的条件。如果调用函数的状态没有向退出条件靠拢,程序很可能陷入死循环。所以我们能得出递归的执行条件
1.实现递归条件
1.基线条件:就是执行函数的退出条件,也就是递归最底层的情况
2.递归条件:就是解决问题的步骤和方法
2.递归举例
public class Repeat {
public static int factor(int n){
System.out.println("函数开始,n=" + n);
if(n == 1){
System.out.println("函数结束,n = 1 ret = 1");
return 1;
}
int ret = n*factor(n-1);
System.out.println("函数结束,n=" + n + "ret = " + ret);
return ret;
}
public static void main(String[] args) {
int n = 5;
int ret = factor(n);
System.out.println("ret=" + ret);
}
}
我们以上面的代码为例,来分析代码在递归中的执行过程
建议:建议我们再初学阶段使用递归解决问题的时候,使用草稿纸画一画递归的步骤,加深印象,避免出错