目录
1. 方法的概念及使用
1.1 什么是方法(method)
1.2 方法定义
方法语法格式
1.3 方法调用的执行过程
方法调用过程
1.4 实参和形参的关系
2. 方法重载
2.1 为什么需要方法重载
2.2 方法重载概念
3. 递归
3.1 递归的概念
3.2 递归执行过程分析
汉诺塔问题
编程中, 某段功能的代码可能频繁使用到, 如果在每个位置都重新实现一遍, 会:
1. 使程序变得繁琐
2. 开发效率低下,做了大量重复性的工作
3. 不利于维护,需要改动时,所有用到该段代码的位置都需要修改
4. 不利于复用
因此,在编程中,我们也可以将频繁使用的代码封装成"方法",需要时直接拿来链接(即方法名--方法的入口地址)使用即可,避免了一遍一遍的累赘。
1. 方法的概念及使用
1.1 什么是方法(method)
方法就是一个代码片段. 类似于 C 语言中的 "函数"。方法存在的意义:
1. 是能够模块化的组织代码(当代码规模比较复杂的时候).
2. 做到代码被重复使用, 一份代码可以在多个位置使用.
3. 让代码更好理解更简单.
4. 直接调用现有方法开发, 不必重复造轮子.
在目前我们写方法的时候, 我们是这样写的:
开头为public static
这个是必须写的,
其次, 后续的样子为:
public static 返回值类型 方法名(形式参数列表){
方法体;
}
public static void add(int a, int b) {System.out.println(a + b);
}
在上面这个例子当中, 和上面的语法形式都是对应的, 返回值是无返回类型void
, 方法名为add
, 形参列表可以有多个int a, int b
, 方法体就是sout
.
当我们运行的时候, 会发现什么都没有, 因为要执行方法需要调用.
完整代码:
public class Test {public static void add(int a, int b) {System.out.println(a + b);}public static void main(String[] args) {int x = 1;int y = 2;// 方法的使用, 将方法的名称写在这里, 通过 方法名() 调用, ()中写的参数是实际参数add(x, y); // ()中的 个数和类型 需要和上面的 add() 一一匹配}
}
执行结果:
这就是Java中一个方法的调用过程.
注意本篇文章中的所有方法都必须加上 public static
, 具体原因以后再说.
1.2 方法定义
方法语法格式
// 方法定义
修饰符 返回值类型 方法名称([参数类型 形参 ...]){方法体代码;[return 返回值];
}
示例: 实现一个两个整数相加的方法
public class Test {public static int add(int a, int b) {return a + b;}public static void main(String[] args) {int x = 1;int y = 2;int ret = add(x, y);System.out.println(ret);}
}
执行结果:
3
【注意事项】
1. 修饰符:现阶段直接使用public static
固定搭配
2. 返回值类型:如果方法有返回值,返回值类型必须要与返回的实体类型一致,如果没有返回值,必须写成void
3. 方法名字:采用小驼峰命名
4. 参数列表:如果方法没有参数,()
中什么都不写,如果有参数,需指定参数类型,多个参数之间使用逗号隔开
5. 方法体:方法内部要执行的语句
6. 在java当中,方法必须写在类当中
7. 在java当中,方法不能嵌套定义
8. 在java当中,没有方法声明一说
到这里我们就清楚了: 为什么要定义方法? 方法由几部分组成?
1.3 方法调用的执行过程
方法调用过程
调用方法 -> 传递参数 -> 找到方法地址 -> 执行被调方法的方法体 -> 被调方法结束返回 -> 回到主调方法继续往下执行
【注意事项】
- 定义方法的时候, 不会执行方法的代码. 只有调用的时候才会执行.
- 一个方法可以被多次调用.
1.4 实参和形参的关系
由于Java的方法和C语言的函数类似, 所以在这里省略该部分内容, 具体参考本人C语言函数博客.
http://t.csdnimg.cn/uz5la
以及传参过程:
http://t.csdnimg.cn/ugQr8
Java中方法的形参就相当于add函数中的自变量a, 用来接收add函数在调用时传递的值的. 形参的名字可以随意取, 对方法都没有任何影响, 形参只是方法在定义时需要借助的一个变量, 用来保存方法在调用时传递过来的值.
注意:在Java中,实参的值永远都是拷贝到形参中,形参和实参本质是两个实体
形参是实参的一份临时拷贝.
2. 方法重载
2.1 为什么需要方法重载
如果我们想求两个数的和, 会写出如下代码:
public class Test {public static int sum(int a, int b) {return a + b;}public static void main(String[] args) {int a = 10;int b = 20;int ret = sum(a, b);System.out.println(ret);}
}
接下来我们的需求变了, 我们要求两个小数的和:
double d1 = 12.3;
double d2 = 12.5;
double ret2 = sum(d1, d2);
System.out.println(ret2);
那么能否直接把d1
, d2
传入上面的sum
? 显然不行. 因为函数的调用需要满足 类型, 个数 都匹配, 而这是两个double
类型, sum
方法却是两个int
类型的参数, 所以我们就要用别的方法.
public static double sumDouble(double a, double b) {return a + b;
}
// main方法改为:
double d1 = 12.3;
double d2 = 12.5;
double ret2 = sumDouble(d1, d2);
System.out.println(ret2);
到这里就会有一个问题, 如果要加其他类型的加法方法, 又得再多写一个方法, 又要重新命名, 这样就十分的麻烦, 那么Java中是支持两个方法的名字是相同的.
也就是说, 可以不用改名字, 方法名都为sum
, IDEA并不会报错.
此时上述 两个返回值为不同类型的sum
方法 就构成了方法的重载.
public class Test {public static int sum(int a, int b) {return a + b;}public static int sum(int a, int b, int c) {return a + b;}public static double sum(int a, double b, int c) {return a + b;}public static double sum(double b, int c, int a) {return a + b;}public static double sum(double a, double b) {return a + b;}public static void main22(String[] args) {int a = 10;int b = 20;int ret = sum(a, b);System.out.println(ret);double d1 = 12.3;double d2 = 12.5;double ret2 = sum(d1, d2);System.out.println(ret2);}
2.2 方法重载概念
在自然语言中,一个词语如果有多重含义,那么就说该词语被重载了,具体代表什么含义需要结合具体的场景。
在Java中方法也是可以重载的。
在Java中,如果多个方法的名字相同,参数列表不同,则称该几种方法被重载了。
注意:
1. 方法名必须相同
2. 参数列表必须不同(参数的个数不同、参数的类型不同、类型的次序必须不同)
3. 与返回值类型是否相同无关
对于使用者来说, 省略了很多记忆成本.
3. 递归
想象一下,你正在试图解决一个复杂的拼图游戏。这个拼图游戏由许多小块的拼图组成,每一块都代表了一部分图像。为了解决这个问题,你首先尝试找到拼图的边缘部分。这些边缘部分的拼图通常会有一些特殊的标记,如颜色或形状,这使得它们更容易从其他拼图中识别出来。
当你找到一块边缘拼图后,你会试图将其放入拼图的适当位置。然后,你可以看到拼图的其余部分是如何与此拼图配合的。一旦你正确地放置了第一块拼图,你可以用同样的方法来解决剩余的拼图。但是,如果没有正确的边缘拼图,你将不得不回到起点并重新开始搜索。
这个寻找和放置拼图的过程就是一个递归的过程。每次你找到一个新的边缘拼图并将其放置到正确的位置时,你都在减小问题的规模。通过递归地解决这个问题,你可以最终完成整个拼图。
在编程中,递归被广泛用于处理这种类型的问题。例如,你可以使用递归来遍历一个树形结构(如HTML文档)或解决一些需要分治策略的问题(如排序或搜索算法)。
有些时候,我们遇到的问题直接并不好解决,但是发现将原问题拆分成其子问题之后,子问题与原问题有相同的解法,等子问题解决之后,原问题就迎刃而解了。
3.1 递归的概念
一个方法在执行过程中调用自身, 就称为 "递归".
递归相当于数学上的 "数学归纳法", 有一个起始条件, 然后有一个递推公式.
例如, 我们求 N!
起始条件: N = 1 的时候, N! 为 1. 这个起始条件相当于递归的结束条件.
递归公式: 求 N! , 直接不好求, 可以把问题转换成 N! => N * (N-1)!
递归的必要条件:
1. 将原问题划分成其子问题,注意:子问题必须要与原问题的解法相同
2. 递归出口
3.2 递归执行过程分析
// 递归输出有序数字public static void function(int a) {if(a == 1) {System.out.println(a);return;}function(a-1);System.out.println(a);}public static void main(String[] args) {function(3);}
观察执行流程:
- 每次递归的时候, 这个函数只执行了一部分, 就去执行另一部分了;
- 归的时候, 会把当前方法的剩余部分执行完毕;
- 递的次数 和 归的次数 是一样的.
汉诺塔问题
/*** @param pos1 起始位置* @param pos2 中转位置* @param pos3 目标位置* @param n*/public static void hanio(int n,char pos1,char pos2,char pos3) {if(n == 1) {move(pos1,pos3);return;}hanio(n-1,pos1,pos3,pos2);move(pos1,pos3);hanio(n-1,pos2,pos1,pos3);}/*** @param pos1 起始位置* @param pos2 目标位置*/public static void move(char pos1,char pos2) {System.out.print (pos1+" -> " + pos2+" ");}
测试一下:
public static void main(String[] args) {hanio(1,'A','B','C');System.out.println();hanio(2,'A','B','C');System.out.println();hanio(3,'A','B','C');}
可以看到, 和我们手动推导的结果是一样的.