4-方法的使用

一.方法的概念及使用

什么是方法?

方法就是一个代码片段. 类似于 C 语言中的 "函数"。它能够做到一份代码在多个位置使用,不必重复造轮子。

比如要判断某一年是不是闰年?

public class test {
    public static void main(String[] args) {
        int year=2023;
        if((year%4==0&&year%100!=0)||year%400==0) {
            System.out.println("是闰年");
        } else {
            System.out.println("是平年");
        }
    }
}

上面一串代码只能判断2023年是不是闰年,那如果想判断2024,2025...年呢,都要把这份大致相同的代码敲一遍未免太不现实,所以可以定义方法来解决。

1.1 方法的定义

方法定义格式

修饰符 返回值类型 方法名称(参数列表){
方法体;
(return 返回值;)
}

例如,我们可以写一个方法判断某个年份是否是闰年

public static boolean isLeapYear(int year){
        if((year%4==0&&year%100!=0)||year%400==0) {
            return true;
        }else{
            return false;
        }
    }

1.现阶段使用修饰符public static即可

2.如果方法有返回值,返回的实体类型必须和返回值类型一致;如果没有返回值,返回值类型写void

3.方法必须写在类中

4.方法不可以嵌套定义

5.在Java中没有方法声明(也就是说,即使某个方法定义在了main方法的后面,main调用它时也不必提前声明)

1.2 方法的调用及执行过程

调用方法很简单,只需要在使用该方法的地方传入参数即可

比如,用刚才的isLeapYear方法判断2023,2024,2025是否是闰年

public static void main(String[] args) {
        System.out.println(isLeapYear(2023));
        System.out.println(isLeapYear(2024));
        System.out.println(isLeapYear(2025));
    }
 //false true false

那么程序在运行的时候是如何调用方法的呢?

调用方法-->传递参数-->找到该方法的地址-->执行被调方法的方法体-->被调方法结束返回-->继续执行下面的代码

1.3 实参和形参的关系

形参和实参的定义

形参只是方法在定义时需要借助的一个变量,用来保存方法在调用时传递过来的值
实参是调用该方法时实际传入的值

再次借用一下上面的代码

public static boolean isLeapYear(int year){//year是形参
        if((year%4==0&&year%100!=0)||year%400==0) {
            return true;
        }else{
            return false;
        }
}


public static void main(String[] args) {
        System.out.println(isLeapYear(2023));
        System.out.println(isLeapYear(2024));
        System.out.println(isLeapYear(2025));
}//2023,2024,2025是实参,在调用时传给year

形参永远只是实参的拷贝,形参和实参是两个实体,形参和实参互不影响

比如,交换两个整型变量的值

public static void swap(int x,int y) {//x,y是a,b的形参
   int tmp=x;//交换x,y的值
   x=y;
   y=x;
}
public static void main(String[] args) {
  int a=10,b=5;
  swap(a,b);
}
//运行结果
x=5 y=10
a=10 b=5

可以看到,在swap函数交换之后,形参x和y的值发生了改变,但是main方法中a和b还是交换之前的值,即没有交换成功

原因分析

实参a和b是main方法中的两个变量,其空间在main方法的栈中,而形参x和y的空间在swap方法运行时的栈中。在swap方法调用时,只是将实参a和b中的值拷贝了一份传递给了形参x和y,因此对形参x和y操作不会对实参a和b产生任何影响。

那么怎么真正交换a和b呢?

可以用数组的方式

public static void  swap(int[] arr) {
        int tmp=arr[0];
        arr[0]=arr[1];
        arr[1]=tmp;
    }
public static void main(String[] args) {
       int [] arr={10,5};
       swap(arr);
        System.out.println(arr[0]);
        System.out.println(arr[1]);
}

或许这个方法在你看来有点low,但是我的能力有限,目前只能给出这一个方法了

总结

对于基础类型来说, 形参相当于实参的拷贝. 即 传值调用

二.方法重载

现在需要一个可以实现两个数比较大小的方法,于是你进行了一顿猛如虎的操作

public static boolean isMax(int x,int y) {
   return x>y?true:false;
}

但是出题人并没有说是让你比较int类型,他想让你比较double和double,double和int...

你在心里把他骂了一通,然后又敲了两段代码

public static boolean isMax2(double x,double y) {
   return x>y?true:false;
}
public static boolean isMax3(double x,int y) {
   return x>y?true:false;
}

然后出题人鸡蛋里挑骨头:“你列了三个比大小的函数,让我怎么记住它们的参数类型啊!”

他的话虽然可恶,但是合理,那么能不能使用同一个名字对不同的参数进行比较呢?

2.1 方法重载的概念

在自然语言中,经常会出现“一词多义”的现象,比如:“好人”,看到这个词时,你会想到扶老奶奶过马路的小学生,还是刚才那位“好人”出题者。一个词语如果有多重含义,那么就说该词语被重载了,具体代表什么含义需要结合具体的场景。

在Java中方法也是可以重载的

方法重载的条件:

1. 方法名必须相同

2. 参数列表必须不同(参数的个数不同/参数的类型不同/类型的次序必须不同)

3. 与返回值类型是否相同无关

来判断一下下面的方法是否构成重载

public static int add(int x,int y) {
     return x+y;
}
public static long add(int x, int y) {
     return x+y;
}

public static double add(double x,double y) {
     return x+y;
}
public static int add(int x, int y) {
     return x+y;
}

第一个是不可以构成重载的,返回值不会对调用方法产生影响

第二个是可以的,它们的参数类型不同

2.2 为什么方法可以重载

在同一个作用域中不能定义两个相同名称的标识符。比如:方法中不能定义两个名字一样的变量,那为什么类中就可以定义方法名相同的方法呢?

因为有方法签名

方法签名即:经过编译器编译修改过之后方法最终的名字。具体方式: 方法全路径名+参数列表+返回值类型,构成方法完整的名字。
public class test {//方法一
    public static int add(int x, int y) {
        return x+y;
    }
    public static double add(double x,double y) {//方法二
        return x+y;
    }  
}

在main方法中分别调用了方法一和方法二,上图是它们经过编译器修改后的名字,()里的字母表示参数类型,()后面的字母显示返回值的类型,其中I表示int,D表示double

如果想要详细了解编译器的方法签名规则,可以看下表

特殊字符

数据类型

V

void

Z

boolean

B

byte

C

char

S

short

I

int

J

long

F

float

D

double

[

数组(以[开头,配合其他的特殊字符,表述对应数据类型的数组,几个[表述几维数组)

L

引用类型,以L开头,以;结尾,中间是引用类型的全类名

看到这里,或许你会疑问,既然返回值的类型也被方法签名标记出来了,为什么不能构成方法重载呢?

实际上答案很简单,虽然在编译完成后的方法签名是不一样的,但是在调用的时候会存在二义性。比如下面这串代码

public static int add(int x,int y) {//方法1
     return x+y;
}
public static long add(int x, int y) {//方法2
     return x+y;
}
public static void main(String[] args) {
        add(3,5);
}

究竟该调用方法一还是方法二是不确定的,所以自然不会编译通过

三. 递归

相信大家肯定都听过这个故事

从前有坐山,山上有座庙,庙里有个老和尚给小和尚将故事,讲的就是:
"从前有座山,山上有座庙,庙里有个老和尚给小和尚讲故事,讲的就是:
"从前有座山,山上有座庙..."
"从前有座山……"

有些时候,我们遇到的问题直接并不好解决,但是发现将原问题拆分成其子问题之后,子问题与原问题有相同的解法,等子问题解决之后,原问题就迎刃而解了,这就是递归的思想

3.1 递归的概念

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

递归相当于数学上的 "数学归纳法", 有一个起始条件, 然后有一个递推公式.

例如, 我们求 N!
起始条件: N = 1 的时候, N! 为 1. 这个起始条件相当于递归的结束条件.
递归公式: 求 N! , 直接不好求, 可以把问题转换成 N! => N * (N-1)!

递归的条件:

1 . 将原问题划分成其子问题,注意:子问题必须要与原问题的解法相同

2 . 终止条件

例如,实现一个方法求n!

public static int fac(int n) {
        if(n==0||n==1) return 1;
        return n*fac(n-1);
        }

上面的方法虽然很简单,却可以帮助我们更好地理解递归

假设n=5

3.2 递归不是万能的

实现一个方法,求斐波那契数列的第n项

0 1 1 2 3 5 8 ...(为了防止被喷,把网址给你们斐波那契数列介绍

public static int fib(int n) {
        if(n==1) return 0;
        if(n==2) return 1;
        return fib(n-1)+fib(n-2);
    }

当我们执行fib(40)的时候,发现程序执行速度极慢. 原因是进行了大量的重复运算.

用下面一个代码验证一下fib(3)被执行的次数

public static int count = 0;//类的成员变量,以后会提到
public static int fib(int n) {
    if(n==1) return 0;
    if(n==2) return 1;
    if(n==3) count++;
    return fib(n-1)+fib(n-2);
}
public static void main(String[] args) {
    System.out.println(fib(40));
    System.out.println(count);
}
//运行结果
63245986
39088169

你会惊奇的发现fib(3)的运行次数如此之多,所以不如直接使用一个循环来求

public static int fib(int n) {
int last2 = 1;
int last1 = 1;
int cur = 0;
for (int i = 3; i <= n; i++) {
cur = last1 + last2;
last2 = last1;
last1 = cur;
}
return cur;
}

此时程序的执行效率也会大大提高

3.3 递归的练习

一. 写一个递归方法,按顺序打印一个数字的每一位

(例如 1234 打印出 1 2 3 4)

 public static void print(int num) {
        if(num<=9) {
            System.out.print(num);
            System.out.print(' ');
        } else {
            print(num/10);
            System.out.print(num%10);
            System.out.print(' ');
        }
}

二. 写一个递归方法,输入一个非负整数,返回组成它的数字之和

例如,输入 1729, 则应该返回1+7+2+9,它的和是19

public static int sum(int num) {
        if(num<10) {
            return num;
        }
        return num%10+sum(num/10);
        }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不 会敲代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值