欢迎光临散文网 会员登陆 & 注册

Java零基础快速入门|方法(下)

2021-02-04 09:47 作者:动力节点小王本王  | 我要投稿



本篇文章主要内容:

方法重载/overload

方法递归

难点解惑


方法重载/overload

关于方法重载是什么,以及怎么进行重载,这些我们目前先不去研究,先来看看以下代码不使用方法重载机制,存在哪些缺点?

运行结果如下图所示:

没有重载,分析缺点

我们可以看到以上三个方法功能“相似”,都是求和,只不过参与求和的数据类型不同, 因此定义了三个方法,分别起了三个不同的方法名。这种方式会增加程序员编程的压力,因为 程序员起码要记忆三个方法名,另外代码也不是很美观。怎么解决呢?我们来看看使用方法重 载机制之后会是怎样,请看以下代码以及运行结果:

那么,什么是方法重载呢?

方法重载(overload是指在一个类中定义多个同名的方法, 但要求每个方法具有不同的参数的类型或参数的个数。调用重载方法时,Java 编译器能通过检查调用的方法的参数类型和个数选择一个恰当的方法。方法重载通常用于创建完成一组任务相似但参数的类型或参数的个数不同的方法。调用方法时通过传递给它们的不同个数和类型的实参来决定具体使用哪个方法。

什么情况下我们考虑使用方法重载呢?

在同一个类当中,如果多个功能是相似的,可以考 虑将它们的方法名定义的一致,使用方法重载机制,这样便于程序员的调用,以及代码美观, 但相反,如果两个方法所完成的功能完全不同,那么方法名也一定要不一样,这样才是合理的。

代码满足什么条件的时候构成方法重载呢?满足以下三个条件:

  1. 在同一个类当中。

  2. 方法名相同。

  3. 参数列表不同:个数不同算不同,顺序不同算不同,类型不同也算不同。

接下来我们来看看以下程序哪些方法构成了方法重载,哪些没有:

哪些方法重载了,哪些没有

编译结果如下图所示:

编译错误信息提示

通过观察以上代码以及测试结果我们得知,方法5和方法4是一样的,这不是方法重载, 这叫“方法重复哈哈”,因为之前我们就说过方法形参中起决定性作用的是参数的数据类型,参数的名字随意,因为每一个形参都是局部变量,变量名自然是随意的。其中方法6和方1相同,显然方法的重载和方法的返回值类型没有关系,这也是合理的,因为之前我们提过,方法执行结束之后的返回值我们可以接收也可以不接收。另外方法7和方法1也无法构成重载, 显然方法重载和修饰符无关。

总之,方法1和方法2要想构成方法重载,首先它们在同一个类当中,方法名一样,参数列表不同类型、个数、顺序),这样 java 虚拟机在运行的时候就可以分清楚去调用哪个方法了。其实,最终要调用哪个方法,还是取决于调用的时候传递的实际参数列表。所以在 java 编程中要区分两个方法,首先看方法名,如果方法名一致,则继续看它们的形式参数列表。

接下来我们来看一下方法重载在实际开发中的应用,你有没有觉得每一次输出的时候“System.out.println();”这行代码很麻烦,我们来封装一个工具类,请看以下代码:

运行结果如下图所示:

测试工具类U

看到以上的代码,你是不是感觉以后要打印数据到控制台就很方便了,代码再也不需要写这么多“System.out.println();”,你只需要“U.p();”,当然,你需要把U.java 文件编译生成的U.class 文件拷贝到你的硬盘当中,一直携带着,什么时候需要的话,把U.class 文件放到classpath 当中就可以使用了。

 

方法递归

什么是方法递归?我们先来看一段代码:

以上代码的执行结果如下图所示:

递归执行结果

我们可以看到以上代码的执行过程中,一直输出“m begin”,“m over”一次也没有输出, 直到最终发生了错误:java.lang.StackOverflowError,这个错误是栈内存溢出错误,错误发生后, JVM 退出了,程序结束了。

实际上以上代码在 m()方法执行过程中又调用了 m()方法,方法自身调用自身,这就是方法递归调用。以上程序实际上等同于以下的伪代码(说明问题,但是无法执行的代码):

说明递归执行原理的伪代码

通过伪代码我们可以看出,m()方法一直在被调用方法中的代码必须遵循自上而下的顺 序依次逐行执行,不能跳行执行,对于栈内存来说一直在进行压栈操作,m()方法从未结束 过,所以没有弹栈操作,即使栈内存足够大也是有限的内存,总有一天栈内存会不够用的, 这个时候就会出现栈内存溢出错误。通过以上研究得出递归必须要有合法的结束条件,没有结 束条件就一定会发生StackOverflowError。我们再来看看有结束条件的递归,例如以下代码:

递归的过程中满足了某个条件,递归结束了

综上所述,递归其实就是方法在执行的过程中调用了另一个方法,而另一个方法则是自己本身。在代码角度来看就是在a()方法中调用a()方法,使用递归须谨慎,因为递归在使用的时候必须有结束条件,没有结束条件就会导致无终止的压栈,栈内存最终必然会溢出,程序因错误的发生而终止。

大家再来思考一个问题,一个递归程序有合法有效的结束条件就一定不会发生栈内存溢出错误吗?在实际开发中遇到这个错误应该怎么办?

一个递归程序有的时候存在合法有效的终止条件,但由于递归的太深,在还没有等到条件 成立的时候,栈内存已经发生了溢出,这种情况也是存在的,所以实际开发中我们尽可能使用 循环来代替递归算法,原则是:能不用递归尽量不用,能用循环代替的尽可能使用循环。当然, 如果在开发中遇到了由于使用递归导致栈内存溢出错误的发生,首先,我们要检查递归的终止 条件是否合法,如果是合法的还是发生栈内存溢出错误,那么我们可以尝试调整堆栈空间的大 小。怎么调整堆栈大小呢,大家可以研究一下下图中的一些参数,这里就不再讲解内存大小的 调整了,这不是初级程序员应该掌握的。

java 虚拟机内存设置参数

接下来我们来研究一下在不使用递归的前提下,完成 1~N 的求和,这个应该很简单,请看下面代码:

运行结果如下图所示:

不使用递归计算 1~N 的和

那么,使用递归应该怎么写呢?请看以下代码:

运行结果如下图所示:

使用递归计算 1~N 的和

我们来使用伪代码对以上代码的执行过程进行分析,请看以下伪代码:

 以上程序的内存变化是这样的,请看下图:

1~N 递归求和内存图

为了加强大家对递归算法的理解,我们再来看一张图:

另一种形式的递归内存图

其实大家把上图逆时针旋转 90 度,你会看到一个栈数据结构对吗?

 

难点解惑

对于本章节内容来说,要求理解的内容较多,其中包括两个难点:

  1. 方法执行过程中内存的变化;

  2. 递归算法

其实只要对方法执行过程中内存的变化有很深入的理解,所有方法执行过程中内存变化都能画出来,递归算法也就理解了。

对于画内存图在这里嘱咐大家几个关键点,以帮助你掌握方法的内存变化以及对递归的理解:

  • 方法体当中的代码必须遵循自上而下的顺序依次逐行执行,当前行代码不结束,下一行代码 是绝对不会执行的;

  • 一定要理解栈数据结构的原理是遵循先进后出、后进先出 原则,每当方法调用时分配空间,此时“进”栈,每当方法执行结束时释放空间,此时“出” 栈。永远都是最后执行的方法最先结束,最先执行的方法最后结束。

小结

本章节内容主要讲解了 Java 中方法相关的语法机制,其实这个在 语言中被称为函数, 一般在开发中我们都会把独立的功能单独定义成一个方法,在需要的时候调用就行了,这样可以让写过的代码得到重复利用。

本章节中对于方法的作用是需要大家理解的,对于方法的定义与调用是需要大家必须掌握 的,另外要求大家对方法的形参和返回值存在的意义有深刻的理解。还有大家要想彻底掌握Java  程序中的方法,还需要对方法执行过程中内存的变化有深刻的理解。另外还要掌握方法的重载机制,以及方法的递归算法。尤其是递归时的内存变化有助于你对递归执行原理的理解。


最后附Java零基础视频教程给大家,配合学习效果更佳!!



Java零基础快速入门|方法(下)的评论 (共 条)

分享到微博请遵守国家法律