Java中的"方法"
在Java中的方法类似在C中的函数,但也有不同之处,Java中没有方法的声明,方法的定义可以在调用前,也可以在调用后。写出一个方法可以重复使用就是方法的意义。
方法的定义语法
public static 返回值类型 方法名称(参数类型 x){
//方法的功能实现
return x;//有返回值则返回,没有则不返回
}
返回值类型
若有返回值,则写上返回值的类型,如int,double等,若没有返回值,即不需要返回,则返回值类型为void。但即使没有返回值也可以使用return,只是return后没有值,作用为提前终止方法。
方法名称
方法名一般使用小驼峰命名法,即有一个单词组成的名字时,名字全小写,多个单词组成的名字时,除第一个单词外,其余单词首字母大写。命名时也应该见名知意,尽量不要用拼音命名。
方法的调用语法
调用一个方法时,只需写出函数名加括号,括号内传入参数,即可实现方法调用。在函数定义完成但没有调用时,函数不会执行。函数内部也是从上到下执行,全部执行完毕后返回,或遇到return可提前直接返回。
函数的参数
参数分为实参和形参,在函数调用过程中,传入函数的参数就叫实参,在函数内部创建的、用来接收实参的叫做形参,可以理解为形参只是实参的临时拷贝,对形参进行的操作对实参不起任何作用。
public static void main(String args[]){
int a = 10;
int b = 20;
change(a,b);
}
public static change (int x, int y){
int tmp = x;
x = y;
y = tmp;
}
上述代码就是一个例子,代码表面看上去在交换a和b,但是实际没有任何作用,因为a和b只是将自己的值临时拷贝一份到形参x,y上去,x和y在函数内部进行交换时,对a和b不会有任何影响,当方法调用结束后,x和y的生命周期结束,值也消失了。
方法的重载
当有时候我们需要处理多种不同参数的时候,就可以用到方法的重载。
方法重载必须满足一下几个要求:
- 多个方法名字一样
- 多个方法参数类型或参数个数不一样
- 只有返回值类型不同不能构成方法的重载
- 多个方法要在一个类中
class Test {
public static void main(String args[]) {
add(1,2);
add(1.5,2.5);
}
public static int add(int x, int y) {
return x + y;
}
public static double add(double x, double y) {
return x + y;
}
}
在上述代码中,就使用到了方法的重载,在同一个类中定义了名称一样,参数不一样的两个加法方法,在主函数中无论传的是两个整数还是两个浮点数,都不会进行报错,这就是方法重载的作用。
方法的递归
方法的递归就是在方法调用过程中,在方法内部自己对自己进行调用,类似数学中的数学归纳法,理解很简单,想到如何去使用,不那么简单。
一般来说使用方法递归需要满足以下条件:
- 问题可拆分,拆分后的问题和原问题只有数据的大小或量级不一样,解决思路一样。
- 需要有终止条件,在递归进行到某一条件时,不需要继续递归即可得出确定值,或者已经实现了某些功能,如打印等。没有终止条件则会陷入无限递归,最终报错。
以下有两道例题可用递归解决,分别为青蛙跳台阶和汉诺塔问题。
青蛙跳台阶问题:
一只青蛙一次可以跳上一级台阶也可以跳上两级台阶。求该青蛙跳上n级台阶总共有多少跳法。
代码实现其实并不难,只需要找到规律,在我不断画图数数的努力下,最终得到的次数为,当有一级台阶时,只有一种跳法,两级时是两种,三级台阶时是三种,四级台阶时是五种,六级八种,七级十三种……,不过规律就是满足斐波那契数列,每此的总方法数都会是前两个方法数的和,那就是满足数学公式,fibo(x) = fibo(x - 1) + fibo(x - 2)。有了这个公式就不难写出如下代码,利用递归,在台阶数为1是已知是1种,在台阶数为2时已知是2种,可以直接进行返回,其余的阶数则需要进行"简化",即在方法内部再次调用该方法,传入更低的阶数,直到1或2。
import java.util.Scanner;
public class Test1 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int steps = scanner.nextInt();
System.out.println(ways(steps));
}
public static int ways(int x){
if (x == 1) {
return 1;
}
if (x == 2) {
return 2;
}
return ways(x - 1) + ways(x - 2);
}
}
汉诺塔问题:
汉诺塔问题是一个经典的问题。汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。问应该如何操作?
这个问题在代码实现前最重要的问题也是进行找规律,当然,又在我不懈的努力下,我最终通过画图后终于得出了如下结论,当柱子上只有一个圆盘时,只需要一步,当有两个时,需要三步,当有三个时,需要七步,四个十五步……,最终的结论即为,当柱子上有n个圆盘时,需要挪动的步数为:2n-1次。根据这个规律,在方法内部的终止条件就可以是当圆盘只降为一个时,可以确定步骤为一,在函数内部进行递归时,传的值都应该是圆盘数量减一,就可得到如下代码。
import java.util.Scanner;
public class Test2 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int layerNum = scanner.nextInt();
System.out.println(hanoi(layerNum) - 1);
}
public static int hanoi(int x){
if (x == 1) {
return 2;
}
return 2 * hanoi(x - 1);
}
}
看来是我之前想得有点简单,本以为只是要求挪动次数,结果是挪动步骤,可以分析得出,在每一次的柱子上只有一个圆盘时,会将这个最大的圆盘挪到目标柱子上,但在有n层的汉诺塔上如果要对最下面的圆盘进行挪动,则势必会将n-1个圆盘按照顺序排放到中间柱上去,然后就可以对最下面的圆盘进行操作,挪完最下面的圆盘后,在中间柱上的n-2个也会按照顺序排列到刚才的起始柱上去,最后一个也会到目标圆盘上,以此类推,可以得到如下代码。
import java.util.Scanner;
public class Test2 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int layerNum = scanner.nextInt();
hanoi(layerNum,'A','B','C');
}
public static void hanoi(int n, char pos1, char pos2, char pos3){
if (n == 1) {
move(pos1,pos3);
return;
}
hanoi(n - 1, pos1, pos3, pos2);
move(pos1,pos3);
hanoi(n - 1, pos2, pos1, pos3);
}
private static void move(char posX, char posY) {
System.out.print(posX + "->" + posY + " ");
}
}
方法的功能是借助pos2,将pos1上的n个圆盘挪动到pos3上去,所以方法需要的参数有四个,分别需要知道当前起始柱是谁,中间柱是谁,目标柱是谁和当前要挪动的圆盘个数。方法的终止条件就是当柱子上只有一个圆盘时,可以直接挪到目标柱上,当有两个及以上时需要使用递归,功能相同只需要改变参数,第一次递归就是上述说的,将起始柱上n-1个圆盘借助目标柱移到中间柱上去,全部进行完后,便可将起始柱的最后一个挪到目标柱上去,然后下一个递归则是将当前中间柱上的n-1个圆盘借助起始柱挪到目标柱上,然后方法结束,很神奇说实话。越来越理解老师说的不要过于注重函数内部实现,都是真理~。