全面分析Java方法的使用与递归
目录
- java中方法的使用
- 什么是方法
- 方法的定义与使用
- 方法如何进行调用及其方法调用过程
- 方法的形参和实参
- 方法重载
- 方法签名
- 递归
java中方法的使用
什么是方法
举一个日常生活中的例子,比如我们在学校班长都会发送消息,比如它想让班级里的每一个人到某某教学楼某某班级进行开会,他就会给每个人发信息,同学今天我们有重要会议要进行开班会请你到某某教学楼某某班级来,如果班长要给每一个人发送信息,一个班里有很多人这样班长发信息就会很累,换个思路,班长要群发消息这样是不就会很省心。这也就是与java中的方法类似,我们定义一个方法实现你需要的功能,在你想要调用并且实现这个功能你就可以任意调用。
在编程中如果重复实现某个功能就会
1.使程序变得繁琐
2.开发效率低下,做了大量重复性的工作
3. 不利于维护,需要改动时,所有用到该段代码的位置都需要修改
4. 不利于复用。
方法的意义:
1. 是能够模块化的组织代码(当代码规模比较复杂的时候).
2. 做到代码被重复使用, 一份代码可以在多个位置使用.
3. 让代码更好理解更简单.
4. 直接调用现有方法开发, 不必重复造轮子
方法的定义与使用
定义规范:
修饰符 返回值类型 方法名称([参数类型 形参 ...]){
方法体代码;
[return 返回值];
}
我们举一个例子:判断是否是闰年:
public static boolean isLeapYear(int year) { if(year%4==0&&year%100!=0||year%400==0) { return true; } return false; }
实现两个数的加法:
public static int add(int x, int y) { //实现两个数的加法 return x + y; }
这样的方法就可以在你需要这个功能的时候进行调用,不需要你在写一遍,减少了代码的冗余。
一些关于方法的注意事项:
1. 修饰符:现阶段直接使用public static 固定搭配
2. 返回值类型:如果方法有返回值,返回值类型必须要与返回的实体类型一致,如果没有返回值,必须写成void
3. 方法名字:采用小驼峰命名
4. 参数列表:如果方法没有参数,()中什么都不写,如果有参数,需指定参数类型,多个参数之间使用逗号隔开
5. 方法体:方法内部要执行的语句
6. 在java当中,方法必须写在类当中
7. 在java当中,方法不能嵌套定义
8. 在java当中,没有方法声明一说
方法如何进行调用及其方法调用过程
举一个例子:还是上面那个例子判断闰年?
public static boolean isLeapYear(int year) { if(year%4==0&&year%100!=0||year%400==0) { return true; } return false; } public static void main(String[] args) { Scanner scan = new Scanner(System.in); System.out.println("请您输入year判断是否是闰年?:>"); int year =scan.nextInt(); if(isLeapYear(year)) { //是闰年 System.out.print(year+"是闰年"); } else { System.out.print(year+"不是闰年"); } }
我们来剖析一下这段代码:
首先我们需要定义一个年份:
调用方法:
我们可以总结一下方法的调用过程大致是:
调用方法--->传递参数--->找到方法地址--->执行被调方法的方法体--->被调方法结束返回--->回到主调方法继续往下执行
注意事项:
只有定义完方法之后才可以调用方法。并且只有调用方法时,方法才会执行。
我们定义的方法可以多次重复调用。完成我们想要完成的需求。
举个实例:计算1!+2!+3!+4!+5!;
这个代码虽然简单但是可以证明我们把一个功能都实现成一个方法,这样我们调用起来,代码逻辑就很清晰,所以建议我们实现一个功能的时候都要把它封装成一个方法。
方法的形参和实参
Java中方法的形参就相当于sum函数中的自变量n,用来接收sum函数在调用时传递的值的。形参的名字可以随意取,对方法都没有任何影响,形参只是方法在定义时需要借助的一个变量,用来保存方法在调用时传递过来的值。
例如:实现一个方法交换两个整型变量
传值调用:
根据上面的答案,并不是我们想要的结果那是为什么呢?
我们来剖析一下:
有的人还会说那我把形参写成 a和b他会交换a和b的值么?
答案并不会,形参的名字可以任意取与名字无关,如果写成a和b那只能说明原来的两人和你形参这两个人是重名的,并不会本质的改变。
那我们究竟怎么才能改变两个数的值呢?
这就与c语言类似,在c语言中是传两个数的地址而在java中传的是引用,引用存储的是这两个变量在内存的地址,通过地址就可以改变。
由于java语言中没有所谓的取地址,在Java中有引用类型,引用类型所引用的变量就是存储在内存当中的地址。通过地址就可以实质的改变某个值。
在java中引用类型有许多比如,类,对象,数组,字符串等等。
我们接下来利用数组进行交换两个数的值。
public static void Swap(int[] array) { int tmp = array[0]; array[0] = array[1]; array[1] = tmp; } public static void main(String[] args) { int[] array =new int[]{10,20}; Swap(array); System.out.println(Arrays.toString(array)); }
为啥两个值交换呢?因为数组是引用类型,引用变量(这里是array)存放的是数组中的元素在内存中的地址,通过地址就可以真正的改变这两个值。
方法重载
百度百科:方法重载是指在一个类中定义多个同名的方法,但要求每个方法具有不同的参数的类型或参数的个数。调用重载方法时,Java编译器能通过检查调用的方法的参数类型和个数选择一个恰当的方法。方法重载通常用于创建完成一组任务相似但参数的类型或参数的个数或参数的顺序不同的方法。 Java的方法重载,就是在类中可以创建多个方法,它们可以有相同的名字,但必须具有不同的参数,即或者是参数的个数不同,或者是参数的类型不同。调用方法时通过传递给它们的不同个数和类型的参数,以及传入参数的顺序来决定具体使用哪个方法。
看上面复杂的概念一时可能看不懂不如我来举一个例子吧。
好比如我们要实现数的加法,要同时实现两个整形的加法,两个浮点数的加法,三个整形数的加法
我们没学过方法重载可能会这么写。
public static int addTwoInt(int a,int b) { return a+b; } public static int addThirdInt(int a,int b,int c) { return a+b+c; } public static double addTwoDouble(double a,double b) { return a+b; } public static void main(String[] args) { int a =10; int b =20; int c =20; double d =3.14; double e =9.89; System.out.println(addTwoInt(a, b)); System.out.println(addThirdInt(a, b, c)); System.out.println(addTwoDouble(d, e)); }
对于学过方法重载的同学看见这个代码真想。。。。。
这样的代码是不是看着很繁琐,每一次实现一个加法就要起一个名。上面的代码需要提供许多不同的方法名,而取名字本来就是让人头疼的事情
那我们接下来使用方法重载又有多大的变化呢?
我们都使用相同的名字在idea不会报错,原因是在java语言中支持方法的重载。
所以,在Java中,如果多个方法的名字相同,参数列表不同,则称该几种方法被重载了
根据这三个代码我们就可以总结出方法重载的规则了
第一:方法名相同;
第二:返回值不做要求;
第三:方法名的参数列表不同(包括参数的返回类型,形参的顺序,形参的个数);
方法签名
既然有方法重载,那java是内部是怎么支持重载的呢?那就要说一说方法签名了。
方法签名即:经过编译器编译修改过之后方法最终的名字。具体方式:方法全路径名+参数列表+返回值类型,构成方法完整的名字。
我们通过找到生成代码的.class文件 然后右键打开powershell
输入一个 javap -v +文件名
回车之后就可以看到java代码的汇编代码,根据汇编代码就可以看到方法的签名。
我们既然定义了相同名字的方法,那编译器是怎么识别我们要调用哪个方法呢?没错这就是方法签名起了作用,每定义一个方法在编译完生成class文件,就会生成一个方法签名,编译器就是根据每个方法的签名不同而识别的,比如你要计算两个double类型的和,那他就会直接找DD的这个签名而不会匹配到其他的签名。
递归
递归定义是数理逻辑和计算机科学用到的一种定义方式,使用被定义对象的自身来为其下定义(简单说就是自我复制的定义)。递归定义(recursive definition)亦称归纳定义,一种实质定义,指用递归的方法给一个概念下的定义
通俗的讲,当我们遇到一个问题,这个问题具有每一步的解法都是相同的,我们就可以将这个大问题分解成多个子问题,最终这个问题就会被解决;
实现递归有两个必要条件:
第一:子问题必须要与原问题的解决方法是相同的。
第二:必须要有判断条件防止递归深度太深导致栈溢出。
我们来举一个经典递归例子:求N的阶乘
我们可以思考一下根据上图的推理第一:他符合原问题的解法与子问题的解法是一致的,有符合判断条件(判断条件就是如果n==1的时候1!=1).这就是递归 从5!被分解成5*4!,4*3!.......
这样的问题就迎刃而解了。
public static int factor(int n) { if(n==1) { return 1; } return n* factor(n-1); } public static void main(String[] args) { System.out.println(factor(5)); }
递归小练习
按顺序打印一个数字的每一位(例如 1234 打印出 1 2 3 4)。
这个题我们怎么思考呢?
首先要得到一个数字的每一位肯定是除10 和模10循环知道数字为0
那我们可以将1234这样来分解;
public static void printEveryNum(int num) { if(num<=9) { System.out.print(num+" "); return; } printEveryNum(num/10); System.out.print(num%10+" "); } public static void main(String[] args) { int num =1234; printEveryNum(num); }
递归求 1 + 2 + 3 + ... + 10 递归实现1一直加到10的和
public static int sum(int num) { if(num==0) { return 0; } return num+sum(num-1); } public static void main(String[] args) { int a =10; System.out.println(sum(100)); }
到此这篇关于全面分析Java方法的使用与递归的文章就介绍到这了,更多相关Java方法与递归内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!