方法(函数)
方法(函数)
一、方法的概念
案例:控制台打印《静夜思》
1 | 床前明月光, |
以现有的知识,使用两种方法打印以上效果。
1 | public class TestFunction{ |
运行结果:
以上代码无论是直接打印,还是使用循环打印,都无法避免冗余的代码。
二、方法的定义与调用
概念:实现特定功能的一段代码,可反复使用。
定义语法:
1
2
3public static void 方法名称(){
//方法主体
}定义的位置:方法定义在类的内部,不能嵌套定义,与main方法并列。
1
2
3
4
5
6
7
8
9//位置1
public class TestDefinitionFunction{
//位置2
public static void main(String[] args){
//位置3
}
//位置4
}
//位置5正确的位置为:
位置2
、位置4
。定义第一个方法
printSign
1
2
3
4
5
6
7
8
9
10
11
12
13
14public class TestFunction{
public static void main(String[] args){
System.out.println("窗前明月光,");
System.out.println("疑似地上霜,");
System.out.println("举头望明月,");
System.out.println("低头思故乡。");
}
public static void printSign(){
for(int i=0;i<10;i++){
System.out.print("-");
}
System.out.println();
}
}方法的调用
在需要执行方法代码的位置,通过方法名称进行调用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public class TestFunction{
public static void main(String[] args){
System.out.println("窗前明月光,");
printSign();
System.out.println("疑似地上霜,");
printSign();
System.out.println("举头望明月,");
printSign();
System.out.println("低头思故乡。");
printSign();
}
public static void printSign(){
for(int i=0;i<10;i++){
System.out.print("-");
}
System.out.println();
}
}运行结果:
调用方法时,会优先执行方法内部代码,结束后,返回到方法的调用处,继续向下执行。
三、方法的参数
- 多数情况下,方法与调用者之间需要数据的交互;调用者必须提供必要的数据,才能使方法完成对应的功能。
- 调用方法时,所传入的数据被称为“参数”。
- 定义时的方法的参数被称为形式参数,调用时方法的参数被称为实际参数。
- 方法的参数可以让代码功能更加灵活、普适性更高,易于修改及维护。
定义语法:
“形参”等价于“局部变量的声明”
1
2
3public static void 方法名称(形式参数){
//方法主体
}调用语法:
“实参”等价于“为形式参数局部变量赋值”
1
方法名称(实际参数);
1.单个参数
1 | public class TestFunction{ |
运行结果:
2.多个参数
1 | public class TestFunction{ |
运行结果:
四、返回值与返回值类型
概念:方法执行后的返回结果。
方法执行后,一些情况下无需放回结果;另一些情况下则必须返回结果。
返回值类型:基本、引用、void,同时实际返回值的类型要与定义的返回值类型一致。
定义语法:
1
2
3
4public static 返回值类型 方法名称(形式参数列表){
//方法主体
return 返回值;
}调用语法:
变量类型要与返回值类型保持一致。
1
变量 = 方法名称();
案例1:
1 | public class TestResultValue{ |
运行结果:
return关键字
一个方法只能有一个返回值
1
2
3
4public static int calc(int a,int b){
return a+b;
return a-b;//错误
}当有返回值的方法存在分支结构时,必须保证每一条分支都具有正确的返回值。
1
2
3
4
5
6
7public static String isEven(int num){
if(num%2==0){
return "偶数";
}else{
return "奇数";
}
}否则将报错:
java: 缺少返回语句
return 的两种用法
应用在具有返回值类型的方法中
1
return value;//表示结束当前方法,并伴有返回值,返回到方法的调用处。
应用在没有返回值类型(void)的方法中
1
2
3
4
5
6
7
8
9return;//表示结束当前方法
public static void show(){
for(int i=1;i<=100;i++){
if(i==50){
return;
}
}
}
注意:return与break的区别,break是跳出循环,如果方法中循环语句下方还有代码,则会继续执行,而return则是结束当前方法,后续代码都不会执行到。
五、方法的多级调用与无穷递归
多级调用
1
2
3
4
5
6
7
8
9
10public class TestNestInvoke{
public static void main(String[] args){
m1();
}
public static void m2(){
System.out.println("m2() start");
System.out.println("m2() end");
}
}运行结果:
无穷递归
当方法自己调用自己时,如果没有正确的出口条件,则产生无穷递归。会造成堆栈内存溢出异常。
1
2
3
4
5
6
7
8
9public class TestRecursionInvoke{
public static void main(String[] args){
m1();
}
public static void m1(){
System.out.println("m1() start");
System.out.println("m1() end");
}
}运行结果:
六、递归
什么是递归?
解决具有既定规律的问题时,在方法内部再次调用自身方法的一种编程方式。
何时使用递归?
当需要解决的问题可以拆分成若干个小问题,大小问题的解决方式相同,方法中自己调用自己;使用循环解决的常规问题,都可以替换为递归解决。
如何正确使用递归?
设置有效的出口条件,可以让调用链上的每个方法都可以正确返回,避免无穷递归。
案例1:
循环阶乘:计算5的阶乘。
循环计算阶乘较为简单,依次与每个值相乘即可。
1
2
3
4
5
6
7
8
9
10
11
12public class TestFactorial{
public static void main(String[] args){
System.out.println(factorial(5));
}
public static int factorial(int n){
int sum = 1;
for(int i=2;i<=n;i++){
sum = sum*i;
}
return sum;
}
}递归阶乘
案例1:求5的阶乘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25public class TestFactorial{
public static void main(String[] args){
System.out.println(getFive(5));
}
public static int getFive(int n){
//return n * 4的阶乘;
return n * getFour(4);
}
public static int getFour(int n){
//return n * 3的阶乘;
return n * getThree(3);
}
public static int getThree(int n){
//return n * 2的阶乘;
return n * getTwo(2);
}
public static int getTwo(int n){
//return n * 1的阶乘;
return n * getOne(1);
}
public static int getOne(int n){
//return 1的阶乘;1的阶乘就是1
return 1;
}
}运行结果:
案例2:案例1中除了1的阶乘,其他的函数都是相同的部分,于是我们可以抽离出来。
1 | public class TestFactorial{ |
运行结果:
分析图:
递进,每一次推进,计算都比上一次变得简单,直至简单到无需继续推进,就能获得结果。也叫到达出口。
回归,基于出口的结果,逐层向上回归,依次计算每一层的结果,直至回归到最顶层。