javaSE 方法的使用(超详细)

一、方法是什么?

1.1定义

方法就是一个代码片段. 类似于 C 语言中的 “函数”.
方法存在的意义(不要背, 重在体会):

  1. 是能够模块化的组织代码(当代码规模比较复杂的时候).
  2. 做到代码被重复使用, 一份代码可以在多个位置使用.
  3. 让代码更好理解更简单.
  4. 直接调用现有方法开发, 不必重复造轮子

1.2基本语法

// 方法定义
public static 方法返回值 方法名称([参数类型 形参 ...]){
 方法体代码;
 [return 返回值];
}
// 方法调用
返回值变量 = 方法名称(实参...);

在这里插入图片描述

代码示例如下:

class Test {
 public static void main(String[] args) {
 int a = 10;
 int b = 20;
        
        // 方法的调用
 int ret = add(a, b);
 System.out.println("ret = " + ret);
 }
    // 方法的定义
 public static int add(int x, int y) {
 return x + y;
 }
}
// 执行结果
ret = 30

注意事项:

  1. public 和 static 两个关键字在此处具有特定含义, 我们暂时不讨论, 后面会详细介绍.
  2. 方法定义时, 参数可以没有. 每个参数要指定类型
  3. 方法定义时, 返回值也可以没有, 如果没有返回值, 则返回值类型应写成 void(比如主方法)
  4. 方法定义时的参数称为 “形参”, 方法调用时的参数称为 “实参”(调用add时候的x,y).
  5. 方法的定义必须在类之中, 代码书写在调用位置的上方或者下方均可.
  6. Java 中没有 “函数声明” 这样的概念(只有方法名称和参数,没有具体的实现)

1.3方法调用过程

基本规则:
定义方法的时候, 不会执行方法的代码. 只有调用的时候才会执行.
当方法被调用的时候, 会将实参赋值给形参.
参数传递完毕后, 就会执行到方法体代码.
当方法执行完毕之后(遇到 return 语句), 就执行完毕, 回到方法调用位置继续往下执行.

class Test {
 public static void main(String[] args) {
 int a = 10;
 int b = 20;
 System.out.println("第一次调用方法之前");
 int ret = add(a, b);
 System.out.println("第一次调用方法之后");
 System.out.println("ret = " + ret);
 System.out.println("第二次调用方法之前");
 ret = add(30, 50);
 System.out.println("第二次调用方法之后");
 System.out.println("ret = " + ret);
 }
 public static int add(int x, int y) {
 System.out.println("调用方法中 x = " + x + " y = " + y);
 return x + y;
 }
}
// 执行结果
一次调用方法之前
调用方法中 x = 10 y = 20
第一次调用方法之后
ret = 30
第二次调用方法之前
调用方法中 x = 30 y = 50
第二次调用方法之后
ret = 80

在这里插入图片描述

关于实参和形参(重点)

代码示例如下:

class Test {
 public static void main(String[] args) {
 int a = 10;
 int b = 20;
 swap(a, b);
 System.out.println("a = " + a + " b = " + b);
 }
 public static void swap(int x, int y) {
 int tmp = x;
 x = y;
 y = tmp;
 }
}
// 运行结果
a = 10 b = 20

在这里插入图片描述
在这里插入图片描述
解决办法:引用数据类型
在这里插入图片描述

1.4方法返回值

比如图例要求1—100中第一个3的倍数,可以用return提前结束方法
在这里插入图片描述

二、 方法的重载

2.1定义(重点,需要记忆)

方法重载发生"在同一个类中",定义了若干个方法名称相同,参数列表不同(参数的类型或者个数不同)的一组方法,与返回值无关!!!这样的一组方法称为重载方法
下图第二个重载方法是参数的个数不相同。
在这里插入图片描述

2.2重载规则

针对同一个类:
方法名相同
方法的参数不同(参数个数或者参数类型)
方法的返回值类型不影响重载。

关于println的提示

没有返回值的方法是不可以用println去打印的
在这里插入图片描述

三、方法的递归

3.1定义

一个方法在执行内部过程中调用自身, 就称为 “递归”.

注意:递归不能只看名字去辨别(第二个方法内部调用的是max的重载后的方法,是两个方法。只有自己调用自己才可以)
在这里插入图片描述
程序能实现方法递归的核心原因∶当在程序中调用另一个函数时,当前程序会暂缓执行,直到调用函数调用结束,当前程序才会继续执行。

3.2调用递归的场景(重难点)

在这里插入图片描述
思维模式(重点掌握):
在写递归函数时,千万不要纠结这个函数内部到底咋实现,而要注意这个方法的语义(这个函数到底有什么功能),你就假设,这个方法已经别人写好了,你只是调用这个方法而已。

示例如下:
在这里插入图片描述
求5的阶乘:可以分成54321,符合递归思路拆成若干个子问题,终止条件就是拆到1就不能再求阶乘值了。这是思考问题的思路,同下面具体实现代码有区别。
在这里插入图片描述
求5的阶乘值(具体化,写代码):实际上就是把问题拆分成5*4的阶乘值,4的阶乘值交给子方法。
在这里插入图片描述
5就相当与num,4的阶乘值交给子方法factor(num-1),不要去想factor(num-1)怎么实现,假设这个方法已经被别人写好了,你就直接调用即可。
在这里插入图片描述
代码示例如下:函数的语义(传入一个正整数就能求出这个整数的阶乘值)

在这里插入图片描述

3.3递归过程分析

这个方法的语义,作用:传入一个正整数就可以求出1+2+…+num的和
拆分问题:num+递归的方法(num-1)
终止条件:num拆分到1时就是加1
在这里插入图片描述

public static int functor(int num){
//边界条件
        if(num==1){
            return 1;
        }
        //语义拼接
        return num+functor(num-1);
    }
}

练习1

写出一个方法,这个方法输入一个非负整数,返回组成这个数的数字之和。
例如1729 =1+7+2+9

public static int functor(int num){
//终止条件
//这个数如果是个个位数直接返回它的值
        if(num<10){
            return num;
        }
        //拆分问题
    //我可以知道这个数的个位是多少,其它位不知道,交给子方法
   //拆分为这个数的个位加上其他位之和
        return num%10+functor(num/10);
    }
}

递归展开图:
递是向下的红色剪头,归是返回的绿色箭头
在这里插入图片描述

练习2(重难点掌握,和常规递归思路不同)

在这里插入图片描述
难点:首先要找到最高位打印,其次还要打印低位(例子在代码倒数两行)
解析:语义,传入一个正整数,按顺序输出这个数字
这个方法没有返回值,应该关注打印内容,不用在意返回值,但它也有归的过程

public static void functor(int num) {
        //终止条件,无需借助任何办法就能知道的结果
        //num<10就是个位数,直接打印本身
        if(num<10){
            System.out.println(num+" ");
            //return的原因是直接结束函数的调用
            return;
        }
   //方法执行到这里知道起码num是个二位数
   //根据方法的语义,不能先打印个位数
   //所以除了个位之外的高位数,我们交给子方法去处理
        functor(num/10);
        //高位已经交给子方法打印好了,还需要打印当前个位
        System.out.println(num%10+" ");
    }
}

练习3(和练习2作对比)

/**
     * 关注方法语义:传入一个正整数可以按低位到高位顺序打印
     * @author hide_on_bush
     * @date 2022/5/16
     */
    public static void printNumReverse(int num){
        //终止条件还是个位数
        if(num<10){
            System.out.println(num+" ");
            return;
        }
        //现在只知道个位数,先打印个位数
        System.out.println(num%10+" ");
        //剩下的其他位置,交给子方法去处理
        //与练习2刚好相反
        printNumReverse(num/10);
    }
}

在这里插入图片描述

3.4斐波那契数列

关于斐波那契数列介绍:
添加链接描述
注意方法的语义:传一个正整数求出该对应的斐波那契数的值,这个正整数代表的是在这个数列中,这个斐波那契数位于第几位。

public static int fib(int n) { 
//终止条件
//该数列第一位和第二位都是1
 if (n == 1 || n == 2) { 
 return 1; 
 } 
 //斐波那契数=当前位置的前两位之和
 //关注语义,理解写法含义
 return fib(n - 1) + fib(n - 2); 
}

练习(重点,青蛙跳台阶,fibo的应用)

一只青蛙一次可以跳上 1 级台阶,也可以跳上2 级。求该青蛙跳上一个n 级的台阶总共有多少种跳法
在这里插入图片描述
可以画个图,当n=3时找规律

/**
     * 关注方法语义:传入一个正整数n可以求出青蛙到这n层一共有几种可能性
     * @author hide_on_bush
     * @date 2022/5/16
     */
    public static int Jump(int n){
        //终止条件
        //只剩最后一层台阶,一种跳法
        //只剩两层,两种跳法
        if(n==2||n==1){
            return n;
        }
        //此时假设只剩最后一步到达第n层,n-1和n-2就是之前的台阶高度
        //剩下最后一层和最后两层之前的情况交给子方法处理
        //还是要关注方法的语义
        return Jump(n-1)+Jump(n-2);
    }
}

3.5汉诺塔问题

在这里插入图片描述
注意事项:
在这里插入图片描述
终止条件:就是只有一个盘子,直接移动到C
当n=1时
在这里插入图片描述
当n>=2时
只可能出现下面这三种情况,不可能有别的情况
在这里插入图片描述

在这里插入图片描述

/**
     * 关注方法语义:传入n个盘子,按按汉诺塔规则移动
     * A上的盘子移动到C,B作为辅助
     * @author hide_on_bush
     * @date 2022/5/16
     */
    public static void hanoiTower(int nDisks,char A,char B,char C){
        //终止条件一个盘子,一步到位,
        //把盘子从A移到C上
        if(nDisks==1){
            move(nDisks,A,C);
            return;
        }
        //核心1:把n-1上的小盘子从A移动到B(辅助作用)
        //A是源头,B是终点
        hanoiTower(nDisks-1,A,C,B);
        //核心2:此时A上只剩第n个,也就是最大的盘子,再从A移动到C
        move(nDisks,A,C);
        //核心3:B上所有的小盘子移动到C上,A是辅助,不做任何操作
        hanoiTower(nDisks-1,B,A,C);
    }
    /**
     * 将编号n的盘子从Source移动到Dest
     * @author hide_on_bush
     * @date 2022/5/16
     */
    private static void move(int nDisks, char sourceTower, char destTower) {
        System.out.println("编号为"+nDisks+"从"+sourceTower+"移动到"+destTower);
    }

总结:不要去纠结方法内部如何实现的,掌握核心语义,并结合图去分析


版权声明:本文为ttthe_shy_原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。