一、方法的概念与使用
1.1. 方法的概念
方法就是一个代码片段. 类似于 C 语言中的 "函数"。方法存在的意义:
- 是能够模块化的组织代码(当代码规模比较复杂的时候)
- 做到代码被重复使用, 一份代码可以在多个位置使用
- 让代码更好理解更简单
- 直接调用现有方法开发, 不必重复造轮子
比如我们要写一个方法来判断某一年是否为闰年,那我们可以写这么一组代码块:
public static boolean isLeapYear(int year){if((year%4==0 && year%100!=0)||year%400==0){return true;}return false
接下来我们在main方法里面对这个方法进行调用,就可以实现对某一年是否是闰年进行判断了。
1.2. 方法的定义
//方法的定义
修饰符 返回值类型 方法名称([参数类型 形参]){方法体代码;return 返回值;
}
public static boolean isLeapYear(int year)
修饰符:public static,现阶段的固定搭配。
返回值类型:boolean。如果方法有返回值,返回值类型必须要与返回的实体类型一致;如果没有返回值,必须写成 void
方法名称:isLeapYear,建议,方法名称的命名采用小驼峰,如Nextnum
参数类型:int
形式参数:year。如果有参数,需指定参数类型,多个参数之间使用逗号隔开;如果方法没有参数,()中什么都不写。
如果我们不写返回值,就会产生如下报错。
注意:1.方法必须写在类当中
2.方法不能嵌套定义。比如下面这段代码,就会显示报错。
public static int Add(int a,int b){public static void fac()
3.在java当中,没有方法声明一说
以下为利用方法判断某一年是否为闰年的完整代码:
public class Main {public static boolean isLeapYear(int year){if((year%4==0 && year%100!=0) || year%400==0){return true;}else{return false;}}public static void main(String[] args) {boolean ret=isLeapYear();//在这个括号里面输入年份System.out.println(ret);}
}
1.3. 方法调用的执行过程
调用方法--->传递参数--->找到方法地址--->执行被调方法的方法体--->被调方法结束返回--->回到主调方法继续往下 执行。定义方法的时候, 不会执行方法的代码。 只有调用的时候才会执行 ,并且一个方法可以被多次调用。
比如我们炒菜的时候,炒菜的过程相当于方法的执行,原材料相当于实参,食材明细相当于形参,步骤相当于方法的定义。
1.4. 形参和实参的关系
方法的形参相当于数学函数中的自变量。形参的名字可以随意取,对方法都没有任何影响,形参只是方法在定义时需要借助的一个变量,用来保存方法在调用时传递过来的值。怎么理解这个形参呢,就比如我们想得到一杯果汁,我们把水果(形参)放入榨汁机(方法),得到了果汁(实参)
对于方法的调用,相当于在栈上开辟内存空间。当方法执行的时候,遇到return或者最后一个花括号执行完毕,就会把该方法开辟的栈帧回收掉。
交换两个整数,代码如下:
public static void main(String[] args) {int a = 10;int b = 20;swap(a, b);System.out.println("main: a = " + a + " b = " + b);}public static void swap(int x, int y) {int tmp = x;x = y;y = tmp;System.out.println("swap: x = " + x + " y = " + y);}
当我们调用这个swap方法时,形参a,b进行了交换,不会影响实参的值,因为运行到return时,a和b的栈帧直接被回收了。
二、方法重载
2.1. 方法重载的概念
public static int AddInt(int a,int b){return a+b;}public static double AddDouble(double a,double b){return c+d;}
当我们写出多个方法时,需要提供不同的方法名,我们会因为取名称而感到头疼,此时我们可以用方法重载来解决这个问题。
方法重载可以理解为自然语言的一词多义,当一个词语如果有多重含义,那么就说该词语被重载了,而在Java语言中也是可以实现重载的。
构成方法重载的条件:1、方法名称一样; 2、参数列表不一样 (个数、类型、数据类型只要有一个不一样就算); 3、返回值没有要求。比如下面这两个方法,编译器就会报错,如下图所示。
public static int Add(int a,int b){return a+b;
}
public static int Add(int a,int b){return a+b;
}
编译器在编译代码时,会对实参类型进行推演,根据推演的结果来确定调用哪个方法,比如下面这段代码:
public static int Add(int a,int b){return a+b;
}public static int Add(int a,int b,int c){return a+b;
}
2.2. 方法签名
既然方法中不能定义两个名字一样的变量,那为什么类中就 可以定义方法名相同的方法呢?
方法签名:经过编译器编译修改过之后方法最终的名字。具体方式:方法全路径名+参数列表+返回值类型,构成方法完整的名字。编译器就会通过这个签名来确定你到底会不会进行方法重载。
三、递归
3.1. 递归的概念
递归就是方法自己调用自己,相当与数学里面的数学归纳法。有一个起始条件, 然后有一个递推公式。很多小伙伴觉得递归比较难的原因呢就是因为递归公式比较难求。
递归的必要条件:1、将原问题划分成其子问题,注意:子问题必须要与原问题的解法相同;2、递归出口
3.2. 递归执行过程分析
比如我们用N的阶乘来演示递归:
public static int fac(int n){if(n==1){return 1;}return n*fac(n-1);
蓝色的箭头表示递的过程,红色的箭头表示归的过程,怎么递就怎么归回来。当n=1时,这个递归就会结束。递归是很浪费内存空间的,每一次递归,就会开辟一块新的内存空间。随着递归次数的增多,开辟的内存空间也会越来越大。
3.3. 递归的结束条件
既然递归是自己调用自己,那我们如果写这么一段代码:
public static void func(){func();}public static void main(String[] args) {func();}
如果没有结束条件或者结束条件不对。我们知道一个栈的内存空间是有限的,如果没有结束条件,则就会溢出,栈就会被挤爆,程序就会出问题。
四、 命令字符串
看下面这段代码
public class Main {public static void main(String[] args) {for(int i=0;i<args.length;i++){System.out.println(args[i]);}}
}
这段代码运行之后不会有任何结果,我们可以这样运行。找到程序文件目录,有一个out文件,打开到以.class为后缀的字节码文件,在文件目录里输入cmd并回车,此时产生一个命令框,在里面输入“java Main(与public修饰的类相同) You are cool and handsome”,然后回车这段字符串就会存到args数组里面。我们可以理解为命令行参数,遍历这个数组,都进行了打印。