Java类和对象系列——前置知识:方法

目录

前言

一、方法的概念以及使用

1.方法的概念

2.方法的定义

3.方法调用的执行过程

4.实参和形参

二、方法重载

1.为什么需要方法重载?

2.方法重载的概念

3.方法签名


前言

在课堂上,老师们经常会讲解一些经典的题目提供给同学们学习,为什么呢?就是因为这些题目经常出现,具有一定代表性,又具有一定难度,向全班进行讲解后,同学们可以在做题过程中遇到类似的题目时可以利用到老师讲解过的解题思路,也避免了多位同学来反复来问老师同一题目,大大减少了老师自身的工作量。Java中的方法也有着相似的作用。

一、方法的概念以及使用

从上面的小例子的引入,我们可以得知方法为什么会产生,为什么Java中会存在方法这一概念:如果有一个功能经常地被使用到,我们如果每次都需要自己将这一功能从头到尾实现一遍,属实十分麻烦,要是可以将这一功能封装好,独立开外,当需要用的时候再拿出来用,就变得很方便了。所以方法就是这样的作用:当某一段代码经常被重复使用时,我们可以将这一小段代码定义为一个方法,需要使用是调用该方法即可。

1.方法的概念

方法就是一个代码片段,类似于C语言中的函数。

方法的意义:

1)有利于代码的复用(即同一段代码的重复使用)

2)减少代码量和程序员的工作量

3)方法是一块独立的代码,可以使代码的整体结构变得更加简洁,逻辑更加明确且清晰

4)有利于维护,当方法出错或者需要修改时,只需修改方法内部,而无需修改每处使用到方法的地方。

2.方法的定义

方法的定义格式如下:

修饰符 返回值类型 方法名称(参数1类型 参数1,参数2类型 参数2……) {
    方法体
    [return 返回值;]
}

修饰符:现阶段我们先固定使用 public static 即可,等学习到类和对象的内容时就会明白的用法意义,才可以拓展其他更多的用法。

返回值类型:如果方法需要返回一个值,则在此处写上返回值的类型,且方法体中需要使用 return+返回值,要注意此处返回的值的类型须对应上方法定义时的“ 返回值类型 ”的类型。如果不需要返回任何值,则在此处写上void,方法体中使用“ return;”来表示方法执行的结束,或者不使用return。

方法名称使用小驼峰命名法。

“()”内为方法的参数列表。当方法需要调用方法者传入某些参数时(方法执行所需要使用到的),则在此处设置所需参数类型和参数名,多个参数之间使用逗号隔开;如果没有则直接省略即可。方法定义时,在此处设置的参数,为形式参数。调用方法处“()”内传入的参数,为实际参数。

花括号内的为方法体,是方法内部执行的全部语句。

注意事项:

1)在Java中,方法必须写在类中;

2)在Java中,不允许嵌套定义方法,但可以嵌套使用方法;

3)在Java中,没有方法声明这一概念,当方法被调用时,程序会全局扫描代码寻找该方法的定义,所以定义在main方法前后都是可以的。

3.方法调用的执行过程

这里先直接抛出方法的大概执行流程,然后再一步步进行剖析:

调用方法 --> 传递参数 --> 找到方法地址 --> 执行被调用方法的方法体内容 --> 被调用方法执行结束后返回 --> 返回到调用方法处继续往下执行

通过这个大概的流程我们可以得知:当我们写下一个方法时,程序正常运行时并不会直接执行该方法,而是只有在该方法被调用时才被执行,并且一个方法可以被调用多次,无论是不是同一调用者。

接下来我们通过一个简单的例子来进一步了解方法的执行过程:

public static void main(String[] args) {
    int a = 10;
    int b = 20;
    System.out.println(add(a, b));
}
public static int add(int x, int y) {
    return x + y;
}

上面是一个很简单的计算两个整数相加然后返回结果的一个方法。对于该方法的调用过程我们通过简洁粗略版本的栈帧图来进行分析。

首先我们需要知道:每次调用方法时,都会在虚拟机栈上开辟一块属于该方法的内存空间,里面存放着该方法运行过程中所创建的变量等内容。当方法执行结束时,该空间就被销毁,在该方法中所定义的变量也全都被销毁,由操作系统对该内存空间进行回收。

当程序执行时,首先调用了 main 方法,此时虚拟机栈上就开辟了一块属于 main 方法的内存空间,我们也可以看到该方法中创建了 a 和 b 两个变量。

当 main 方法执行到第三行时,就调用了 add 方法,此时虚拟机栈中就开辟了一块属于它的内存,并且可以看到还创建了变量 ret 来接收形参 x 和 y 相加之后的结果。

当方法内 return 时,就代表方法执行的结束,因此当 add 方法返回时,将返回值带回到调用方法处,然后属于它的这块内存空间就被销毁了。本例中为 main 方法中的第三行。然后调用方法处继续往下执行,本例中为打印本次调用方法后的返回值。

当 main 执行完了之后,属于它的内存空间也被销毁了。

4.实参和形参

实参,为实际参数,是我们调用方法时所传递的参数;

形参,为形式参数,它只是方法在定义时用来接收实参的变量,只是用来保存一下方法被调用时所传递的实际参数的值。

形参的名字可以随意取,和方法相同或者不相同都可以,因为它们所存放的内存空间是不同的,因此作用域也不同,不会相互影响。

我们还是采用上面的例子来进行说明,假设这次的 add 方法中的形参与实参名字相同:

public static void main(String[] args) {
    int a = 10;
    int b = 20;
    System.out.println(add(a, b));
}
public static int add(int a, int b) {
    return a + b;
}

由栈帧图我们可以知道,形参和实参分别放在了 add 方法所属的内存空间和 main 方法所属的内存空间,在不同空间下的变量是互不影响的,因此形参取什么名字都是可以的。 

因此我们可以得知:

在Java中,实参的值永远都是拷贝到形参中而已,形参和实参是两个不同的实体。

我们也可以引出另一个经常遇到的问题所需的结论:

非引用类型参数的形参,其改变不会影响实参。

例如:

public class Test {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        System.out.println("交换前:");
        System.out.println("a = " + a);
        System.out.println("b = " + b);
        swap(a, b);
        System.out.println("交换后:");
        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }
    public static void swap(int a, int b) {
        int tmp = a;
        a = b;
        b = tmp;
    }
}

swap 是一个交换两个整数的方法,如果按照我们所设想的,最后输出的结果应该为 a 为20,b 为10。

但结果并非如此,此时我们就应该调试来发现问题所在:

当我们进行调试,走到方法体内并进行完交换后,发现确实如我们所设想的一样,两个整数进行了交换:

但是出了这个方法之后,当我们返回到调用方法处时,却发现:main方法中的两个整数并没有受到影响。

这便说明:对于基本数据类型,形参进行改变并不会影响实参,因为他们是两块不同内存下的变量,不会互相影响,形参改变不会影响到实参。

二、方法重载

当你在地铁上给老人或者小孩让座时,他们会夸赞“ 你是个好人 ”;当你跟暗恋的女孩子表白时,她也会对你说“ 你是个好人 ”。虽然这是同样的一句话,但是在不同场景就是不同的意思了。在Java中,相同名字的方法,也可以代表不同的含义和作用——方法重载。

1.为什么需要方法重载?

在日常开发中,我们难免会在调用方法时,传递不同类型的参数或者不同的参数个数。于是乎,便有了方法重载的出现,方法重载就是来解决我们调用方法时需要传递不同参数列表的需求的。

2.方法重载的概念

在Java中,方法重载就是:多个方法的方法名相同,而参数列表不同。

public static int add(int a, int b) {
    return a + b;
}
public static int add(int a, int b, int c) {
    return a + b + c;
}
public static double add(double a, double b) {
    return a + b;
}

例如上面代码中,有着三个 add 方法,但是他们的参数列表各不相同。当编译器在编译代码时,会对实参类型进行推演,根据推演的结果来确定调用哪个方法。也即是:当你调用 add 方法时,传递的是两个整数,编译器就会帮你调用上面代码中的第一个 add;如果传递的是两个 double 类型的参数,那就是调用第三个 add 。

参数列表的不同可以为:参数个数不同、参数类型不同、参数顺序不同这三种中任选一个即可(多个当然也是可以的)。

需要注意的是:方法重载对于方法的返回值并无要求,可以相同也可以不同。

3.方法签名

我们都知道,在同一作用域内,不能定义多个相同的标识符,例如在同一方法中,不能定义两个变量名相同的变量,那么为什么在同一个类中,却可以进行方法重载,定义多个方法名相同的方法呢?其实很简单,原因便是:真正的方法名并不只是我们所看到的定义时给出的方法名字而已。

public class Test {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        double d = 10;
        double dd = 20;
        
        add(a, b);
        add(d, dd);
    }
    public static int add(int a, int b) {
        return a + b;
    }
    public static double add(double a, double b) {
        return a + b;
    }

}

例如上面代码中,我们对 add 方法进行了方法重载,然后我们将这段代码编译之后,使用 JDK 自带的 javap 反汇编工具便可以查看其字节码文件中的内容,从汇编代码中我们便可以更好地研究方法真正的名字。

具体操作如下:

对当前文件右键之后按上图操作,即可打开当前文件所在位置:

然后返回上一级,来到 out 目录下:

 

然后一直点击之后,便可以看到当前文件编译之后的字节码文件了

然后如下操作:在目录中输入 cmd 打开控制台

 

 来到控制台后,输入指令:javap -v 加上字节码文件名(注意javap和“ - ”之间有空格)

然后就可以查看到编译之后的字节码文件内容。

上面标注出来的,才是方法真正的名字。

例如:#6 这一行中的“ add:(II) I ”

其中,add为方法定义时的名字,括号内两个“ I ”代表该方法的两个参数都为 int ,括号外的“ I ”表示返回值为 int 。

然后继续往下翻,也可以发现我们上述说到编译器自动根据推演的实参类型调用对应的方法这一结论的证据:

上图中,分别调用了“ #6 ”和“ #7 ”对应的 add 方法。 

因此我们便知道了方法真正的名字不只是我们定义时所给出的名字那么简单,于是有了方法签名的概念。

方法签名即是:经过编译器编译修改过之后方法的最终名字。具体格式为:方法全路径名+参数列表+返回值类型,构成了方法完整的名字,就如上图中所示。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值