在以前的c语言学习中我们解题经常会使用到函数,那么本节将介绍在Java里面的函数(方法),这一节博客呢主要讲了在Java中方法定义,使用,传参和重载,以及递归的学习,帮助你能有更好的解题思路和方法!
JavaSe之方法的使用
一. 方法概念及使用
1.1 什么是方法(method)
方法就是一个代码片段. 类似于 C 语言中的 “函数”。
- 是能够模块化的组织代码(当代码规模比较复杂的时候).
- 做到代码被重复使用, 一份代码可以在多个位置使用.
- 让代码更好理解更简单.
- 直接调用现有方法开发, 不必重复造轮子.
简洁明了来说,就是你想学JavaSE的时候,可以直接来看我的博客,调用我写的博客里面的知识点来学习,同时,别人也可以调用我的博客进行学习,想要学习的时候就特别方便了。
1.2 方法定义
语法格式:
举例方法的使用:
1.两个数的相加:
上面的就是方法,和c语言中的函数一样,int就是方法返回值类型,add就是方法名,(int a,int b)就是形式参数列表。那么我们想要调用这个方法,就必须做到一下两点:
- 拿到这个方法的方法名
- 参数列表要一一对应【个数,类型,顺序】
2.闰年的判断:
注意:此处程序运行的时候,遇到return就直接结束了,所以不需要else。
注意事项:
- 修饰符:现阶段直接使用public static 固定搭配
- 返回值类型:如果方法有返回值,返回值类型必须要与返回的实体类型一致,如果没有返回值,必须写成void
- 方法名字:采用小驼峰命名
- 参数列表:如果方法没有参数,()中什么都不写,如果有参数,需指定参数类型,多个参数之间使用逗号隔开
- 方法体:方法内部要执行的语句
- 在java当中,方法必须写在类当中
- 在java当中,方法不能嵌套定义
- 在java当中,没有方法声明一说
1.3 方法调用的执行过程
方法调用过程:
调用方法—>传递参数—>找到方法地址—>执行被调方法的方法体—>被调方法结束返回—>回到主调方法继续往下执行
当方法被调用时(方法在Java中本质上都是按值传递),会在栈上开辟一块内存,实参传递到形参上面之后,遇到return返回函数的时候,方法开辟的内存就会被销毁。
注意:
- 定义方法的时候, 不会执行方法的代码. 只有调用的时候才会执行。
- 一个方法可以被多次调用。
我们这里再举一个之前提到的例子:计算1!+2!+3!+4!+5!
但是这次我们调用方法来写
我可以详细讲述一下步骤,fac方法就是计算n的阶乘,facSum方法是在fac方法外嵌套一个循环,让它能计算一个任意的数值,然后主函数调用的时候就可以计算了
1.4 实参和形参的关系(重要)
方法的形参相当于数学函数中的自变量,Java中方法的形参就相当于sum函数中的自变量n,用来接收sum函数在调用时传递的值的。形参的名字可以随意取,对方法都没有任何影响,形参只是方法在定义时需要借助的一个变量,用来保存方法在调用时传递过来的值。
代码示例: 交换两个整型变量
输出结果:
我们可以清晰的看到,他们在进行一系列操作之后并没有交换成功,那么问题出在哪呢?我们可以回忆起以前学的c,函数调用可以取地址,但是在Java里并没有取地址,Java做不到,在栈上的地址是拿不到的,由于此处我们学的东西还较少,所以目前无法做得出来,后面更新数组我们就可以做这一题了,到时候会再讲一次这一题。
在Java中,实参的值永远都是拷贝到形参中,形参和实参本质是两个实体,在swap方法调用时,只是将实参a和b中的值拷贝了一份传递给了形参x和y,因此对形参x和y操作不会对实参a和b产生任何影响。对于基础类型来说, 形参相当于实参的拷贝. 即 传值调用
1.5 没有返回值的方法
方法的返回值是可选的. 有些时候可以没有的,没有时返回值类型必须写成void。
一般情况下我们建议要返回值,因为没有返回值类型的话,我们在计算或者引用了方法之后,想要再去对方法返回的值进行操作的时候,它是不支持的。
二. 方法重载
2.1 为什么需要方法重载
经过上面的学习我们可以知道,返回值类型不同是无法调用方法的,比如我们方法里的返回值是int类型,然而我们实参想传递一个double类型的数,这时候就会产生错误,无法编译。那么我们这时候就要学习方法的重载了,它可以有效帮我们解决这个问题。
2.2 方法重载概念
在Java中,如果多个方法的名字相同,参数列表不同,则称该几种方法被重载了。
如下列代码:
从上面我们可以看到并没有报错,而且可以推断出方法重载的条件:
- 方法名相同
- 参数列表不同(个数,顺序,类型)
- 返回值没有要求(前提是不影响方法的重载)
- 编译器在编译代码时,会对实参类型进行推演,根据推演的结果来确定调用哪个方法
(真正确定重载的 是方法名和参数列表)
2.3 方法签名
方法签名即:经过编译器编译修改过之后方法最终的名字。
具体方式:方法全路径名+参数列表+返回值类型,构成方法完整的名字。
一段重载代码经过编译之后,然后使用JDK自带的javap反汇编工具查看,具体操作:
- 先对工程进行编译生成.class字节码文件
- 在控制台中进入到要查看的.class所在的目录
- 输入:javap -v 字节码文件名字即可
具体操作:
一段重载代码生成之后,在文件夹里找到相应的IDEA目录文件名
就好比我来说,我生成了日期目录
然后打开目录,找到out文件夹
一直顺势点进去之后,会发现有你再src命名的文件夹,后缀名为XXX.class
按住Shift+鼠标右键
点进去,我们会看到以下画面
然后输入javap -v 字节码文件名就可以看到如下反汇编代码了
I 代表 int,D 代表 double,那么我们也可以详细做一做了解关于方法签名中的特殊符号。
三.递归(迭代)
3.1贴近生活中的事情
生活中的例子如下图,一个女孩子拿着镜子对着镜子照,于是形成了镜子中间有镜子,一直循环。
这里的重要信息就是:自身中又包含了自己,该种思想在数学和编程中非常有用,因为有些时候,我们遇到的问题直接并不好解决,但是发现将原问题拆分成其子问题之后,子问题与原问题有相同的解法,等子问题解决之后,原问题就迎刃而解了。
3.2 递归的概念
一个方法在执行过程中调用自身, 就称为 “递归”.
例如:我们写一个这样的代码
无限的套用自己,也算是递归吗?我们运行起来,发现出了错误
我们可以看到出现了栈溢出错误,因为这个循环没有终止条件,导致它在栈帧上循环开辟空间,最后栈帧内存装不下了,就会导致溢出。
总结上面的例子,我们引出了如下递归条件:
- 调用自己本身
- 有一个趋近于终止的条件(终止条件从某种意义上来讲,其实就是起始条件)
- 写递归需要提前推导它的递推公式
例如求一个5的阶乘:
代码从上到下依次执行,当执行if语句时,发现不符合,便执行tmp里的方法,又调用一次自己,直到n等于1,然后开始反方向再带值计算。此处再注意一点,就是当打印的是一组序列时,它的打印结果会是从终止值开始打印,而不是按照代码执行顺序打印出来。
3.3 递归练习
例一:按顺序打印一个数字的每一位(例如 1234 打印出 1 2 3 4)
这一题的思路需要很明确,如下图示范:
由图可知我们每次想得到一位数字,都要先模10再除10,所以循环公式找到了
但此题需要注意的一点就是图中红色圆圈这一点,由我上面提到的,一般序列打印的话,是反向打印,如果按照正常来,输入123,结果会是321,与预期不符,所以红色圈这里两句顺序很重要,具体的草图我就不做图解了,有不理解的小伙伴都可以来问我哦~欢迎大家一起讨论
例二:递归求 1 + 2 + 3 + … + 10
思路:sum(10) = 10 + sum(9) --> sum(9) = 9 + sum(8)…循环公式就找到了
例三: 写一个递归方法,输入一个非负整数,返回组成它的数字之和. 例如,输入 1729, 则应该返回1+7+2+9,它的和是19
思路:
由图可知每次都需要除上一个10,再模去一个10,就能得到相应的数字,循环公式就找到了。
例四:求斐波那契数列的第 N 项(0、1、1、2、3、5、8、13、21、34、……)
我们可以发现斐波那契数列从第二项开始,每一项都是前两项之和,所以通式找到了
当等于前两项的时候,它是需要我们去打印的,从第三项开始之后电脑可以算出来
但是第n项比较大时,会发现程序越来越慢,经过分析,它在执行的时候,做了很多重复的计算,在计算第n项时,其中第n-1项算一次,第n-2项又算了一次,所以当n越来越大时,程序会进行很慢,可以知晓这也是递归的一个弊端。
递归特点:
- 代码行数少
- 逻辑比较清楚
- 理解起来比较难
所以此处我们又引出来了循环
就拿例四来说:
我们前面两个if语句就是给第一项和第二项定值,后面的for循环就是让每次循环的时候,第三个数都能成为第一项和第二项的和,避免了上面递归的重复计算,所以这一题循环在时间,空间和效率上更胜一筹。
循环的特点:
- 理解起来很简单
- 代码量比较多
那我们方法的使用就到此为止啦,还是比较简单的,大家有什么建议都可以和博主分享啦,一起加油进步~