形参个数可变:是JDK1.5以后提出的一个概念,指允许为方法指定个数不确定的形式参数的一种特殊的方法传参机制。
上一更新提到,Java的形式参数的个数、类型、顺序都必须与实际参数一一严格对应,那么我现在有这么一个需求:我们有一个buy()方法实现购买饮料的功能,形式参数是这样的,谁去买(学号代替)、每个人哪个品种(饮料名),但是我具体不知道有多少个形式参数,因为喝饮料的学生不确定的。
对于这个问题的解决,有方案一,思路是:定义一个int类型的形参,作为去购买的学生学号,一个String类型的数组,存放饮料名,但是数组有个特性,长短不可变,那么我们把长度定义成全班的人数,喝的人赋值饮料名,不喝的人赋值为null,最后判断不为null的就是喝饮料的,实现代码如下:
public static void main(String[] args) {
int id = 200123;
String[] types = {"可乐",null,"雪碧",null,null,"果粒橙"};
buy(id, types);
/*
* 运行结果:
* ----------------------------
* 饮料由学号为200123的同学去购买,购买的列表:
* 可乐
* 雪碧
* 果粒橙
*/
}
static void buy(int id, String[] types){
System.out.println("饮料由学号为"+id+"的同学去购买,购买的列表:");
//foreach循环
for(String type : types){
if(type != null){
System.out.println(type);
}
}
}
功能也实现了,但是因为JDK1.5以后提出了形参参数个数可变的特性,那么,这个问题就变得简单了,如下:
public static void main(String[] args) {
int id = 200123;
buy(id, "可乐","雪碧","果粒橙");
}
static void buy(int id, String ... types){
System.out.println("饮料由学号为"+id+"的同学去购买,购买的列表:");
//foreach循环
for(String type : types){
System.out.println(type);
}
}
结果也是一样的,来了解一下语法:
返回值 方法名(形参类型 ... 形参名称){}
语法比较简单,只要在参数类型与参数名称之间添加 ... 即可,其他的遵循方法的参数机制就好,有一个注意点,如果有不同类型的参数的时候,这种方法只能用一次,且放在最后,所以:
//正确用法
void buy(int ... a){}
void buy(int x,char ... y){}
//不正确用法
void buy(int ... a,char b){}
void buy(int x,char ... y,String z){}
方法递归:方法的递归简单来说就是,方法自己调用自己,那么方法自己调用自己不是永远结束不了,成了死循环了嘛,所以有一个条件,递归一定要向已知的方向递归,也就是说递归必须能够结束。
来解一道数学题:有一个数列, , , ,那么求 是多少?分析一下:要想知道f(10)的值,必须知道f(9)和f(8)的值,因为f(10)=f(9)+f(8),要知道f(9)的值必须知道f(8)与f(7)的值,如此类推下去,直到f(0)与f(1)的值,再反向计算得出结果。代码如下:
public static void main(String[] args) {
System.out.println(fn(10));//10497
}
public static int fn(int n) {
if(n == 0){
return 1;
}
if(n == 1){
return 4;
}
return 2*fn(n - 1) + fn(n - 2);
}
在代码中 2*fn(n - 1) + fn(n - 2); 属于在方法中自己调用自己,就是递归了,而n==0与n==1的时候属于递归的结束条件,这里只用if不用if-else的原因是,如果程序执行了return语句,就不会向下执行,直接退出方法,关于return关键字在前面也简单介绍过了。
递归在一些算法中经常会用到,且在文件操作时,遍历文件夹也是用的递归,而这两个例子会在后续陆续的展示出来。
方法的重载(Overload),这个概念和方法的重写(Override)经常会混用,其实二者的区别很大,关于重写在后续才会接触到,这里简单的介绍一下重载,在遇到重载时,把两个概念单独拿出来详细介绍。
方法的重载,就是允许在一个类中定义多个方法名相同,但形式参数不同的同名方法。
这里有两个要素:
方法名相同
参数列表相同
方法名相同就是严格的大小写都相等;而参数列表不同包括:类型不同、类型的顺序不同、个数不同,而不包括参数名不相同,且与返回值无关。
举例来看:
//合法的重载
void test(){} void test(int i){} 个数不同
void test(int i){} void test(char c){} 类型不同
void test(int i, char c){} void test(char c, int i){} 类型顺序不同
//不合法的重载
void test(int i){} void test(int c){} 类型名不同
void test(int i, char c){} void test(int c, char i){} 类型名不同
void test(int i){} int test(int i){return i;} 返回值不同
只需要了解到两个不同的要素就可以很好的分辨是不是重载了。
应用:重载主要用于成员方法、构造方法等方法,用在同样功能,但不同参数的同一方法上,使程序更加具有合理的逻辑性,使得调用者者不需要记住同一种方法的多个实现方法的方法名。举例如下:
/*
* 不用重载
*/
//输出10次int变量
void print1(int x){
for(int i=0; i<10; i++){
System.out.println(x);
}
}
//输出10次String变量
void print2(String s){
for(int i=0; i<10; i++){
System.out.println(s);
}
}
不用重载的时候,调用者要记得int类型的调用哪一个,String类型的调用哪一个,如果有其他类型(像Java的自定义类也是一个自定义类型),这么多类,用户同一个操作要记得的方法就十分多了,可能会有print 1 2 3 4 ... 111 112 ...,但是用到了重载以后,如下:
/*
* 使用重载
*/
//输出10次int变量
void print(int x){
for(int i=0; i<10; i++){
System.out.println(x);
}
}
//输出10次String变量
void print(String s){
for(int i=0; i<10; i++){
System.out.println(s);
}
}
调用者只需要记住print这一个方法名就可以了,这给编程带来了极大的便捷性。