【Java SE】方法的使用

简介: 可能学过C语言的小伙伴就知道,C程序是由许许多多的函数组成的,而每个函数对应着一个功能,比如很多的一些库函数,还有我们自己会写一些函数,其实在Java中,我们把函数称作方法,如果从广义上讲,就是来帮助我们解决问题的,既然是解决问题,我们也可以把所有函数都写在main函数内部啊,那如果我们其他地方也需要呢?

1、方法的简述和概念

1.1 什么是方法?

可能学过C语言的小伙伴就知道,C程序是由许许多多的函数组成的,而每个函数对应着一个功能,比如很多的一些库函数,还有我们自己会写一些函数,其实在Java中,我们把函数称作方法,如果从广义上讲,就是来帮助我们解决问题的,既然是解决问题,我们也可以把所有函数都写在main函数内部啊,那如果我们其他地方也需要呢?复制粘贴?这样太麻烦了,这里会造成大量的重复代码,增加了重复性工作,使得程序变得更繁琐,更不利于我们的维护,同时也不利于我们复用,所以为了解决这些问题,我们就出现了方法,当我们需要的时候,调用即可。

如果你还在纠结方法的好处有哪些?那请把我上面列举不使用的方法的缺点反过来,你就知道方法的好处了

这里举个例子,假设我要判断 n 的阶乘,我在main函数写了他的实现,在很下面很下面,我又需要求阶乘了,我又得去拷贝上面的求阶乘代码,还得改一下参数,这样行不行,可行!但是不方便,难不成我一个程序需要求10个数的阶乘,我有10段重复代码,那给阅读者也带来很不好的体验,接下来,我们正式进入方法的学习:

1.2 方法的定义和使用

我们就来写一个求阶乘的方法,首先我们需要知道方法的语法格式是什么:

可能看到上面这些术语的时候还有很多小伙伴不懂,什么是修饰符,这里我们需要注意如下点:

  • 修饰符:在目前我们用 public static 搭配即可,当后期讲到的时候在细说
  • 返回类型:如果没有返回值,可以必须写成 void,如果有,返回的类型必须与实体类型一致
  • 方法名称:统一采用小驼峰命名,不要使用拼英,不要过度缩写,不要使用中文!
  • 参数列表:如果不需要参数则不写,如果有参数,一定要写明参数类型,多个参数之间用逗号隔开
  • 方法体:方法需要执行的语句,遇到 return 则返回
  • 方法必须写在类中,方法不能嵌套定义,没有方法声明的说法
  • 方法只有被调用的时候才执行,结束后回到主调方法继续往下执行

当我们拿到求阶乘的值,我们首先应该思考,阶乘是指 1 * 2 * 3 .... * n,这求的就是 n 的阶乘,首先这个函数肯定有返回值,需要产生 1~n 个连续的整数,再者我们需要拿一个变量每次把乘积存起来,这个变量的初始值不能为0, 有了这种思路,就可以开始写代码了:

那么我们写这样一个方法有什么好处呢?如果我们后续代码还需要求阶乘,是不是就可以直接调用这个函数传参即可?不仅增加了代码可读性,还更利于我们的操作。

1.3 形参与实参的关系

这里如果我们要写一个方法交换两个变量的值,于是聪明的张三就赶忙敲起键盘,不到 30 秒写完了以下代码:

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

可是运行起来发现并没有交换,如果有学习过C语言的小伙伴可能就明白了,形参并不会改变实参的值,为什么呢?因为形参只是实参的一份临时拷贝,那我们传地址,拿指针变量接收,可以吗?不可以!Java中没有所谓的指针。那我们如何解决呢,这里我们先不解决,等到后面学习引用类型,问再来拿这个例子出来修改,如果现在解决了,你也会马马虎虎的弄不懂。

形参呢只是在方法定义的时候,需要借助的变量而已,本质上是用来保存方法在调用时传过来的值,在Java中,实参的值永远都是拷贝到形参当中,本质上他们是两个实体。

什么是形参和实参呢?实参就是在调用方法时方法名括号后面中的参数,形参就是来源于方法的调用,可以理解他是实参的临时拷贝,在方法调用结束,栈帧空间会销毁。

1.4 方法的返回值

  • 如果方法没有返回值,是不能拿变量去接收返回值的!也不能链式访问,否则会报错!
  • 如果方法有返回值,并且方法中有分支情况,我们需要保证每个分支对应都有返回值!

具体细节我们会随着学习的深入而感受到,这里只是让你知道如何使用,在后续的学习中,等你有了一定的代码量,这其中的理论你都能明白。

2、方法重载

2.1  为什么需要方法重载?

在C语言中,我们经常写过求两个数和的函数,通常我们会写成 int 类型参数,导致于这个函数,只能进行整数求和,如果我们要进行浮点数求和,那只能在取一个名字,改成 double 类型参数,如果我们要进行三个数的求和?那我们需要写多少个函数啊?取名字也成了一件头疼的事情,可想而知,在以后的项目中,我们碰到的情况可能会更复杂,那我们可以不可以让他们都是一个函数名呢?显然C语言中是不可以的,但是Java中有了方法重载的概念,我们往后看:

2.2 方法重载的使用

在语言中,如果我们想让相同的方法名,但是可以实现不同的功能,就可以用到方法重载了,在Java中,如果多个方法的名字相同,参数列表不同,则称之为该几种方法被重载了

这里我们就来实现一下上面说的,一个 add方法名 实现两个整型相加,两个浮点数相加,三个整型相加:

在使用方法重载的时候,我们是一定要注意几个点的:

  • 方法名必须相同
  • 返回值类型无所谓
  • 方法形参列表必须不同(顺序不同,个数不同,类型不同)

如果你让方法重载,你仅仅是因为返回值的类型不同的话,就比如你本来是 int类型 返回值,你直接改成 double 类型返回值,这样是不能构成方法重载的,那这里又有小伙伴有疑问了,那编译器怎么知道我使用的哪个方法呢?它会根据我们的实参类型进行推演,来判断我们使用的是哪个方法。具体还需要下来多多尝试写代码,才能理解更深刻。

2.3 方法的签名

在有上面的学习之后,可能很多小伙伴有疑问,我之前在C语言中写函数的时候,不能出现命名一样的函数,编译器会告诉我函数重定义了,那为什么Java中方法重载后可以同名呢?其实本质上的名字是不一样的,方法签名就是编译器编译之后修改方法的最终名字,具体的方式:方法路径全名+方法参数列表类型+返回值类型,这样才能构成完整的方法名。

public class TestDemo {
    public static void main(String[] args) {
        System.out.println(add(1, 2));
        System.out.println(add(1, 2, 3));
        System.out.println(add(1.2, 2.3));
    }
    public static int add(int x, int y) {
        return x + y;
    }
    public static int add(int x, int y, int z) {
        return x + y + z;
    }
    public static double add(double x, double y) {
        return x + y;
    }
}

如果证明我们上面的结论呢?在代码如上代码编译之后,会生成字节码文件,我们可以进入生成字节码文件(.class)所处的文件夹,从地址栏输入cmd命令进入控制台,接着执行我们 javap -v 字节码文件名 就可以查看了:

方法的特殊字符说明:

image.png

3、方法的递归

递归其实在方法执行的过程中不断的自己调用自己,既然是递归,从字面意思看,他就有两个动作,一个是递,一个是归,如果一直递的话,不往回归的话,结果可想而知,是会造成无限递下去,最终导致栈溢出,为什么一直递归下去会导致栈溢出呢?

调用方法时是在JVM栈内存上开辟空间的,方法的递归,本质也是调用方法,如果要调用方法,就会形成栈帧,栈的空间是有限的,如果你一直形成新的栈帧,总会导致栈空间耗尽的情况,这就是栈溢出。  

栈溢出错误

所以由上我们就能得出一个结论:递归肯定不能无限递归下去,一定要有一个递归终止条件,也就是递归的出口。

那么我们如何使用递归解决问题呢?

我们首先得了解方法的调用过程,这个在上面已经说过了,在者我们要找到递推公式,就好比我们求 5!一样,5!可以分为 5 * (5 - 1)!,那么 (5-1)!也就是 4!也可以分成 (4 - 1)!这样重复下去,我们也就产生了一个递推公式:N!=  N*(N-1)!

有了思路,我们如何实现代码呢?那么终止递归条件是什么呢?当我们发现 N 的值为 1 了,也就是 1!自然也是 1,这个时候我们就可以直接 return n;代码实现如下:

public class TestDemo {
    public static void main(String[] args) {
        System.out.println(factorial(5));
    }
    public static int factorial(int n) {
        if (1 == n) {
            return n;
        }
        return n * factorial(n - 1);
    }
}

为了方便大家更好的理解,我们画递归展开图,3的阶乘:

对于递归来说,需要多写代码,多做练习,像我们后续Java数据结构会用递归实现二叉树, 当然递归也不一定是最优的解决方法,就比如斐波那契数列,使用递归的话时间复杂度会很高,会出现很多冗余的运算,并没有循环来的快,这里我们就要根据实际情况来决定了。至于递归的练习题,大家可以自己去找一找,多练习练习。

本期我们只是知道方法该如何使用,还不是特别能看出来方法的重要性,等往后学习,我们就会慢慢慢把学习知识串联起来,那个时候就会明白更多,学习是循环渐进的过程,很多进步都是在写代码的途中产生的,请坚持下去。

相关文章
|
2月前
|
消息中间件 Java Kafka
在Java中实现分布式事务的常用框架和方法
总之,选择合适的分布式事务框架和方法需要综合考虑业务需求、性能、复杂度等因素。不同的框架和方法都有其特点和适用场景,需要根据具体情况进行评估和选择。同时,随着技术的不断发展,分布式事务的解决方案也在不断更新和完善,以更好地满足业务的需求。你还可以进一步深入研究和了解这些框架和方法,以便在实际应用中更好地实现分布式事务管理。
|
2月前
|
Java
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
101 9
|
3天前
|
存储 Java 索引
Java快速入门之数组、方法
### Java快速入门之数组与方法简介 #### 一、数组 数组是一种容器,用于存储同种数据类型的多个值。定义数组时需指定数据类型,如`int[]`只能存储整数。数组的初始化分为静态和动态两种: - **静态初始化**:直接指定元素,系统自动计算长度,如`int[] arr = {1, 2, 3};` - **动态初始化**:手动指定长度,系统给定默认值,如`int[] arr = new int[3];` 数组访问通过索引完成,索引从0开始,最大索引为`数组.length - 1`。遍历数组常用`for`循环。常见操作包括求和、找最值、统计特定条件元素等。
|
2天前
|
算法 Java API
Java 方法注释:规范、实用和高质量的写法
本文深入探讨了如何编写高质量的 Java 方法注释
24 11
|
2天前
|
SQL Java 数据库连接
【潜意识Java】Java中JDBC过时方法的替代方案以及JDBC为什么过时详细分析
本文介绍了JDBC中一些常见过时方法及其替代方案。
21 5
|
2月前
|
安全 Java 开发者
Java中WAIT和NOTIFY方法必须在同步块中调用的原因
在Java多线程编程中,`wait()`和`notify()`方法是实现线程间协作的关键。这两个方法必须在同步块或同步方法中调用,这一要求背后有着深刻的原因。本文将深入探讨为什么`wait()`和`notify()`方法必须在同步块中调用,以及这一机制如何确保线程安全和避免死锁。
60 4
|
2月前
|
Java
深入探讨Java中的中断机制:INTERRUPTED和ISINTERRUPTED方法详解
在Java多线程编程中,中断机制是协调线程行为的重要手段。了解和正确使用中断机制对于编写高效、可靠的并发程序至关重要。本文将深入探讨Java中的`Thread.interrupted()`和`Thread.isInterrupted()`方法的区别及其应用场景。
84 4
|
2月前
|
Java 数据处理 数据安全/隐私保护
Java处理数据接口方法
Java处理数据接口方法
32 1
|
2月前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
149 4
|
2月前
|
Java 测试技术 Maven
Java一分钟之-PowerMock:静态方法与私有方法测试
通过本文的详细介绍,您可以使用PowerMock轻松地测试Java代码中的静态方法和私有方法。PowerMock通过扩展Mockito,提供了强大的功能,帮助开发者在复杂的测试场景中保持高效和准确的单元测试。希望本文对您的Java单元测试有所帮助。
464 2