如果需要经常做某一操作,则需要重复写类似的代码,比如查找某个数。此外,某些复杂的操作需要分成多个步骤进行,以便理解和维护。
为此,计算机引入了函数的概念,用来减少重复代码,分解复杂操作。
与数学中的函数类似,Java 函数又称方法,有方法名,参数(0或多个,类比 x ),结果(0或1个,类比 y)。
方法的基本结构
修饰符 返回值类型 函数名(参数类型 参数名, ...) {
// 操作
return 返回值;
}
public static void test(int a){
System.out.println(a);
}
- 修饰符
可选,有权限修饰符、static、final、abstract 等。
- 返回值类型
如果没有返回值,返回值类型设为 void;
如果返回值类型不为 void,则必须返回,且 return 返回值的数据类型和声明的返回值类型必须一致。
- 参数
可选,也叫形参,由参数类型和参数名组成,可以看成作用域在方法内的局部变量,负责接收外部参数,调用方法时传递参数实际就是给形参赋值。
可变参数:个数不定的参数,必须是参数列表的最后一个,一个方法内只能有一个可变长度参数。语法是在数据类型后面加三个点 ...
,会转换为数组。
public static int getSum(int... a){
// todo
return 0;
}
- return
return
用于显式结束函数执行,返回调用方,没有 return 时,执行到方法结尾自动返回调用方。
可选,返回值类型为 void 时,return 不是必需的。
return 可以用于方法内的任何地方,可以结合选择结构来提前结束方法执行,返回调用方。
public static void test(){
int a = 1;
int b = 2;
if(a == b){
return;
}
System.out.println("a 不等于 b");
}
函数可以调用同一个类中的其他函数,也可以调用其他类中的函数。
方法重载
同一个类中,方法名相同,参数签名不同,称为方法重载,与返回值无关。
参数签名不同指:参数类型不同 或 参数个数不同 或 参数类型顺序不同。
public class Math {
public static double max(double a, double b)
public static float max(float a, float b)
public static int max(int a, int b)
public static long max(long a, long b)
}
⭐方法调用的参数匹配
调用方法的时候,参数传递实际上是给参数赋值,传递的数据类型需要与函数声明的参数数据类型兼容,在没有重载的情况下,只要可以进行类型转换,就会调用该方法,在有重载的情况下,会调用最匹配的方法。
char a = 'a';
char b = 'b';
System.out.println(Math.max(a, b));
⭐方法调用的基本原理
程序从 main 方法开始执行,碰到函数调用的时候,会跳转进函数内部,函数返回后会继续执行调用后面的语句,返回到 main 方法并且 main 方法没有要执行的语句后程序结束。
方法调用可以看作无条件跳转,跳转到方法对应的指令处开始执行,方法执行完毕或者遇到 return 语句的时候,再无条件跳转回调用处,执行方法调用后的下一条指令。
计算机系统使用栈内存来存放方法调用过程中需要的数据,包括参数、返回地址以及方法内定义的局部变量,返回值不太一样,可以简单认为内存中存在一个专门的 返回值存储器
。
栈是一块内存,一般是先进后出,类似于一个桶,往栈里放数据称为入栈,最下面称为栈底,最上面称为栈顶,从栈顶拿出数据通常称为出栈。栈一般是从高位地址向低位地址扩展,栈底的内存地址是最高的,栈顶的是最低的。
每调用一次方法,都会将相关方法的数据入栈,调用结束出栈,main 方法的数据在栈的最下面。
public class Sum {
public static void main(String[] args){
int d = Sum.sum(1,2);
System.out.println(d);
}
public static int sum(int a,int b){
int c = a + b;
return c;
}
}
如上,程序从 main 方法开始执行,main 方法入栈,main 方法有一个 args 参数用来接收用户输入,然后定义了一个局部变量 int d
,接收 sum 方法的返回值。
调用 sum 方法,sum 方法入栈,传入参数 1、2 以及返回地址,sum 方法中定义了一个局部变量 int c
,存储参数 a + b 计算的结果,最后 return 返回。
在返回之前,返回值暂时保存到了专门的返回值存储器中。
在返回之后,指令指示器跳转到返回地址处,sum 方法出栈,然后继续往下执行 main 方法。
递归调用
方法自己调用自己叫递归调用。
递归方法自己调用自己,直到遇到终止条件才会 return 返回,而方法调用主要是通过栈来存储相关数据,每调用一次方法就会在栈内存中开辟一块空间,当递归调用次数过多时,可能导致内存溢出,不建议使用。
public static int factorial(int n){
if(n == 1){
return 1;
}
return n * factorial(n-1);
}
/**
* 汉诺塔问题
*/
public class HanNuoTa {
public static void run(int num,char a,char b,char c){
if(num < 1) {
System.out.println("请输入正整数");
} else if(num == 1) {
System.out.println(a + " --> " + c);
return;
} else {
run(num - 1, a, c, b);
System.out.println(a + " --> " + c);
run(num - 1, b, a, c);
}
}
public static void main(String[] args) {
run(3,'A','B','C');
}
}