文章目录
- 什么是方法
- 如何定义方法
- 方法的调用过程
- 形参与实参的关系
- 方法的重载
- 为什么要重载
- 重载的概念
- 方法签名
- 递归
什么是方法
在C语言的学习中我们学习到了一个概念叫做函数,那么在Java的语法中有没有类似函数的东西的,答案是有的,但是在Java的语法中不叫函数,我们成为方法。什么是方法呢?我们通过一段代码来体会一下方法:
public static int add(int x,int y ) {
return x + y;
}
public static void main(String[] args) {
int x = 10;
int y = 20;
int z = add(x,y);
System.out.println(z);
int a = add(1,44);
System.out.println(a);
}
上面的代码我们就定义了一个可以实现两个数相加方法,这样看这个方法的作用不是很明显,因为方法中完成的功能十分简单,如果功能十分复杂并且在项目中这个功能被使用多次,难道每次使用我们都要重新写一遍码?我们可以把这个功能用方法模块化起来,每次使用只需要调用方法就可以了。所以总结一下方法的功能:
1、当一个功能十分复杂时,方法可以模块化的组织代码
2、方法可以做到让代码重复使用,在多个位置使用
3、让代码更好理解
4、直接调用现有的开发方法,不需要重复造轮子。
如何定义方法
好了我们知道了什么是方法之后,我们该如何在自己的代码中使用方法呢?让我来告诉大家:
方法的语法格式
访问修饰符 返回值类型 方法名称 (参数类型 形参…) {
方法体代码;
return 返回值;
}
使用这样的语法我们就可以在我们的代码中定义一个方法,让我们来尝试写一个求两个数的较大值的方法吧:
public static int max(int x,int y) {
return x > y ? x : y;
}
这样我们就写了一个求最大值的方法,我么来对这个方法分析一下:
public static
:访问修饰符,现阶段直接使用public static
固定搭配
int
:返回值类型
max
:函数的名字
(int x , int y)
: 形参
return x > y ? x : y;
:返回值
花括号里面的就是方法体
方法写完了,我们该如何使用方法呢?定义方法的时候方法不会执行的,只有我们调用的时候方法才会被执行,并且方法可以被多次调用。
方法名(参数类型 实参…)
我们来调用一下我们的方法:
public static int max(int x,int y) {
return x > y ? x : y;
}
public static void main(String[] args) {
int max = max(5,8);
System.out.println("第一次调用:" + max);
int max2 = max(10,50);
System.out.println("第二次调用:" + max2);
}
上面就是我们执行的结果。
方法的调用过程
我们先来大致的说一下方法的调用过程,我们调用方法 - > 传递参数 - > 找到方法的地址 - > 执行被调用方法的方法体 - > 被调用的方法结束返回 - > 回到主方法继续执行。
我们先写一个简单的代码:
public static int add(int x , int y) {
return x + y ;
}
public static void main(String[] args) {
int a = 10;
int b = 20;
int num = add(a,b);
System.out.println(num);
}
那么这个方法是如何被调用的呢?我们通过画图来向大家解释:
最后当add方法结束后,在栈上为add方法开辟的空间会被回收,之后返回主方法继续执行,当主方法执行完毕,主方法的空间也会被回收。
形参与实参的关系
我们来看一段代码:
public static void swap(int x ,int y) {
int tmp = x;
x = y;
y = tmp;
}
public static void main(String[] args) {
int a = 10;
int b = 20;
swap(a,b);
System.out.println(a);
System.out.println(b);
}
这个swap方法会不会把交换a和b两个变量的值呢?我们执行以下看看结果
答案是并没有,原因是什么呢?在上面我们介绍了方法调用的过程,我们知道了在调用时swap方法和main方法各自开辟属于各自的栈帧,ab变量在main函数所在的栈帧中,而xy在swap所在的栈帧中,ab变量和xy变量,没有任何关系,所以我们交换了xy并不会对ab的值造成任何影响。总结以下:在swap方法调用时,只是将实参a和b中的值拷贝了一份传递给了形参x和y,因此对形参x和y操作不会对实参a和b产生任何影响。
方法的重载
为什么要重载
先让我们来看一个例子吧,还是求两个数相加的方法
public static int add(int x,int y ) {
return x + y;
}
public static void main(String[] args) {
int a = 10;
int b = 20;
double c = 10.3;
double d = 9.9;
int e = add(a,b);
System.out.println(e);
}
现在我写了一个返回值类型为int
参数类型为int ,int
的方法,但是现在两个int
类型的变量相加我们可以使用这个add
方法,如果我们有两个double
类型的变量,就不可以使用add
方法了,有一个非常简单粗暴的方法,就是我们再写一个方法。
public static int add(int x,int y ) {
return x + y;
}
public static double add_double(double x,double y) {
return x + y;
}
public static void main(String[] args) {
int a = 10;
int b = 20;
double c = 10.3;
double d = 9.9;
int e = add(a,b);
System.out.println(e);
double f = add_double(c,d);
System.out.println(f);
}
上面的代码解决了问题,但是我们需要提供许多不同的方法名,而取名字本来就很让人头疼,我们是否可以将所有名字都写成add
呢?这时就要使用到我们的方法重载了。
重载的概念
在我们的日常生活中,经常会出现一词多义的现象,例如:你的女朋友对你说你是个好人和你帮助他人时,别人对你说的你是个好人,所代表含义是不一样的。出现这样的情况我们就可以说该词被重载了。在Java中,如果多个方法的名字相同,参数列表不同,则称该种方法被重载了。
public static int addNum(int x ,int y) {
return x + y;
}
public static double addNum(double x ,double y) {
return x + y;
}
public static int addNum(int x ,int y ,int z) {
return x + y + z;
}
public static double addNum( double x , int y ) {
return x + y;
}
public static void main(String[] args) {
int a =addNum(10,20);
double b = addNum(10.4,2.5);
double c = addNum(10.4,5);
int d = addNum(10,20,30);
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
}
上面这个代码演示了Java中方法的重载,有些地方值得我们注意:
1、重载时方法名必须相同
2、参数列表必须不同(参数的个数、类型、次序不同)
3、与返回值类型是否相同无关
4、编译器在编译代码时,会对形参类型进行推演,根据推演的结果来确定调用哪个方法
这样写是不行的,因为重载与返回值类型是否相同无关。有点同学会想到了,我们把名字都写成一样的化,如果这个方法重载了很多次我记不住自己写了那些方法怎么办呢?我们的IDEA非常的聪明,会在我们调用方法时给出我们提示:
方法签名
有些兄弟在看完重载后会产生一些疑问,为什么在方法内定义变量,不可以定义两个名字一样的变量,在类中的方法就可以定义两个一模一样名字的方法呢?这就要提到方法签名了,在经过编译器编译修改之后的方法最终的名字我们成为方法签名。
具体方式方法全路径名 + 参数列表 + 返回值类型构成方法完整的名字。
我们可以在编译过后,使用JDK自带的javap反汇编工具查看方法签名:
1、先对工程进行编译,生成.class字节码文件
2、在控制台中进入到.class所在的目录
3、输入java -v 字节码文件名即可
递归
在C语言函数部分的学习中,我们也曾提到递归的概念,简单来说就是一个函数自己调用自己,我们就称为递归,那么我们就可以类比出,在Java中的递归就是方法自己调用自己。对递归的概念不太熟悉的可以去看看博主的这篇文章:函数的递归
我们通过一道练习题来感受如何使用Java实现递归吧,我们使用递归求n的阶乘:
public static int getNum(int x ) {
if(x == 1) {
return 1;
}
return x * getNum(x - 1);
}
public static void main(String[] args) {
int num = getNum(5);
System.out.println(num);
}
这样我们就完成了题目,是不是跟C语言中的递归方式一样呢。最后总结一下递归的两个必要条件吧:
1、需要有递归的出口,上面代码当形参等于 1 时 就是递归的出口
2、将原问题划分成其子问题,注意:子问题必须要与原问题的解法相同
递归还有一些经典例题,例如汉诺塔问题,他家可以看看我的这篇文章:经典递归问题汉诺塔 这篇文章使用的C语言完成了汉诺塔问题,大家可以尝试着使用Java实现一下。