快来看看,你对Java中可变参数的方法了解多少?
J2SE 1.5 提供了Varargs机制(可变参数),允许直接定义能和多个实参相匹配的 形参 。
之前都是用“数组包裹实参”的办法解决实参个数可变的情况。
从而,可以用一种更简单的方式,来传递个数可变的实参。更大的提高了方法的 重!用!性!
Varargs 的含义
【大体说来,“ Varargs ”是“variable number of arguments”的意思。有时候也被简单的称为“variable arguments” 】
方法声明的语法:
修饰符 返回类型 方法名(普通类型的形参,可变参数类型的形参){
}
方法声明的示例:
public static void method(String str,int…args){
}
注意哦:形参的“类型”与“参数名”之间加上三个连续的“.”(即“…”,英文里的句中省略号),就可以让它和不确定个实参相匹配
方法使用说明:
1 、方法中,对可变参数的处理 为数组类型, 我们通过看 源码 得知
编译器会在背地里把这最后一个形参转化为一个数组形参,并在编译出的class文件里作上一个记号,表明这是个实参个数可变的方法。
所以:在方法体中,我们可以把args当做一个数组来使用,数组童鞋有的,我也都有,比如length属性,比如也可以通过循环遍历数组的每个元素
示例:
public static void method(String str, int …args){
int sum =0;
for ( int i=0;i<args.length;i++){
sum+=args[i];
}
System. out .println(str+”的总成绩是:”+sum);
}
2 、调用带有可变参数的方法时,可变参数的实参值可以为0个,可以为多个,也可以为数组哦
如调用 public static void method(String str, int …args){} 时
以下语法皆可以:
method(“john”);
method(“john”,1,2);
method(“john”,1,2,3);
method(“john”,new int[]{1,2,3});
3 、可变参数要放在形参列表的最后
好吧,我们通过反推法,假如可以放在前面,比如
public static void method( int …args,int a){}
试问,如何得知 调用该方法 时,method(1,2,3),到底是1 2 3为可变参数的实参值,还是什么??
所以容易混淆,JVM是不允许发生这!种!现!象的!
4 、形参列表中至多允许一个可变参数 ,道理同3
示例:
public static void method(String a,int…b,int…c){} ×
public static void method(String a,int…b,String…c){} ×
看到这里,是不是对可变参数的方法,有了一定的了解了啊,那就试着做一套题目吧。
题目一:可变参数+多态
public class TestSub {
public static void main(String[] args) {
Base base=new Sub();// ①
base.add(1,2,3); // ②
}
}
class Base {
public void add (int a, int… arr ){
System.out.println(“base”);
}
}
class Sub extends Base{
public void add(int a, int[] arr ){
System.out.println(“sub_1”);
}
public void add(int a , int b, int c ){
System.out.println(“sub_2”);
}
}
试问打印结果?
80%的小伙伴会认为是 sub_2吧,哈哈,恭喜你!!!
,猜!错!了!
正确答案:sub_1
原因是:执行②时,步骤为 先检测父类Base中有无定义满足该实参列表的方法add,如果没有,则编译报错。如果有则继续检测子类Sub中有无重写,而因为可变参数会被解析成数组类型(通过反编译源码得知),所以认为 add(int a,int[] arr)为其重写 的方法!!!
题目二:可变参数+ 泛型
我们都知道的,泛型和可变参数都是J2SE1.5出现的新特性,如果这两个合在一起,会是神马效果呢?好期待哦
public static void method(T…args){ }
问题:是否编译通过?
正确答案:不可以。( 你猜对啦吗?)
原因是:J2SE 1.5中的泛型机制的一个内在约束——不能拿用标识符来代表的类型来创建这一类型的实例。在出现支持没有了这个约束的Java版本之前,对于这个问题,基本没有太好的解决办法。
不过,传统的“用数组包裹”的做法,并不受这个约束的限制。
比如,可以写成:
public static void method(T[] args){ }
题目三:可变参数+自动装拆箱
如果可变参数 遇上 自动装拆箱呢?
public class OverloadingSampleC {
public static void main(String[] args) {
testOverloading(1, 2);
testOverloading(new Integer(1), new Integer(2));
}
private static void testOverloading(int… args) {
}
private static void testOverloading(Integer… args) {
}
}
正确答案: 两句调用都会报编译错误的哦
原因是:容易出现混淆喽,Java是不允许出现这种情况的,所以直接报错啦
题目四:何必为难编译器
public class OverloadingSampleB {
public static void main(String[] args) {
testOverloading(1, 2, 3);//①
}
private static void testOverloading(Object… args) {
System.out.println(“周芷若 “);
}
private static void testOverloading(Object o, Object… args) {
System.out.println(“赵敏 “);
}
}
试问调用后的打印结果?
是不是很纠结?哈哈
你都这样纠结,更何况编译器了,所以…
正确答案:编!译!报!错!
原因是:这就不用问原因了吧,
对这种现象编译器很为难的哦
题目五:最后一题喽,看看调用完的打印结果
public class OverloadingSampleA {
public static void main(String[] args) {
testOverloading(1);//①
testOverloading(1, 2);//②
testOverloading(1, 2, 3);//③
}
private static void testOverloading(int i) {
System.out.print(“A\t”);
}
private static void testOverloading(int i, int j) {
System.out.print(“B\t”);
}
private static void testOverloading(int i, int… more) {
System.out.print(“C\t”);
}
}
说实话,你是不是稍微有些
呢,嘻嘻,好吧公布答案啦
正确答案:A B C
原因是: 实参个数固定的版本优先
总之哦,和J2SE1.5前 “用数组包裹”的做法相比,真正的实参个数可变的方法,在调用时传递参数的操作更为简单,含义也更为清楚。不过,这一机制也有它自身的局限,并不是一个完美无缺的解决方案。