因为在先前学习java的过程中,有涉及到可变参数,但没有太深入的去学习。所以最近自己找了些相关资料,想加深了解。下面就是学习整理后的内容了。
在JDK1.5后,定义方法时,可以使用同类型个数不确定的参数。
使用可变参数定义方法时,方法实际上是把这些不确定数目的参数隐式地都装进一个数组中, 然后方法再从这个数组中取出元素来使用。
也就是说,方法使用可变参数,和JDK1.4中方法使用数组参数时的处理方式是一样的,都是取出数组元素来使用。
一、定义方法:
返回值 方法名(参数类型...可变参数名)
1 void method(String...args) { 2 3 }
二、调用方法:
1 class VarArgsTest { 2 public static void method(String... str) { 3 4 } 5 6 public static void main(String[] args) { 7 method(""); 8 method("aaa"); 9 method("aaa", "bbb"); 10 } 11 }
三、使用注意事项:
1.一个方法中只能有一个可变参数,并且可变参数必须位于参数列表的最后位置。否则,虚拟机无法判断传递进方法中的参数值是属于哪一个参数。
2.在方法内部可以直接把可变参数当成是数组来处理:
1 void print(String...args) { 2 for (String str : args) { 3 System.out.println(str); 4 } 5 }
3.若在类中有固定参数和可变参数的两个同名方法(重载),调用方法时的实参也可匹配它们的参数列表,会优先选择使用固定参数的方法。
1 class VarArgsTest { 2 3 public void print(String... args) { 4 for (int i = 0; i < args.length; i++) { 5 System.out.println(args[i]); 6 } 7 } 8 9 public void print(String test) { 10 System.out.println("----------"); 11 } 12 13 public static void main(String[] args) { 14 VarArgsTest test = new VarArgsTest(); 15 test.print("hello"); //结果为---------- 16 } 17 }
4.避免带有可变参数的方法重载。
以下是错误的:
1 class VarArgsTest { 2 3 public void print(String... args) { 4 for (int i = 0; i < args.length; i++) { 5 System.out.println(args[i]); 6 } 7 } 8 9 public void print(String test,String...args) { 10 System.out.println(test); 11 } 12 13 public static void main(String[] args) { 14 VarArgsTest test = new VarArgsTest(); 15 test.print("hello","hi"); //编译不通过,因为java虚拟机不知道调用哪个方法。 16 } 17 }
以下是容易犯错误的:
1 class VarArgsTest { 2 3 public void print(String test,Integer... is) { 4 for (int i = 0; i < is.length; i++) { 5 System.out.println(is[i]); 6 } 7 } 8 9 public void print(String test,String...args) { 10 for (int i = 0; i < args.length; i++) { 11 System.out.println(args[i]); 12 } 13 } 14 15 public static void main(String[] args) { 16 VarArgsTest test = new VarArgsTest(); 17 // 当调用print方法,只传递一个实参时,即代表传递给可变参数的实参为空null。 18 // 这时就无法从null判断可变长度参数的类型,java虚拟机不知道该调用哪个方法,发生错误。 19 // 所以在这种情况下,传递的参数如果为空,必须要通过定义变量为空的形式来确认实参的类型。 20 String str = null; 21 test.print("hello",str); 22 // test.print("hello", null); //编译不通过,因为java虚拟机不知道调用哪个方法。 23 } 24 }
5.子类中可用数组的形式参数列表的方法,来重写父类中带有可变参数的方法。
原因从文章开头的说明中也可知道,实际上方法是把可变参数看成是一个数组来处理的,这才导致重写成功。
这应该算一个特例,因为两个方法的参数列表是不一样的,也能实现重写。
下面是一个具体例子:
1 class VarArgsTest { 2 3 public static void main(String[] args) { 4 5 // sub向上转型。 6 Base base = new Sub(); 7 base.print("hello"); //这里编译成功,因为涉及类型提升,调用方法时,是根据父类的参数列表来判断实参是否符合, 8 //而执行的是子类方法的具体内容,输出Sub......test。 9 10 // sub没有转型。 11 Sub sub = new Sub(); 12 sub.print("hello"); //这里编译不成功,因为调用的是sub自身的方法,参数不符合方法中的参数列表。 13 } 14 } 15 16 // 父类 17 class Base { 18 void print(String... args) { 19 System.out.println("Base......test"); 20 } 21 } 22 23 // 子类 24 class Sub extends Base { 25 26 void print(String[] args) { 27 System.out.println("Sub......test"); 28 } 29 }
6.调用带有可变参数,且参数类型为Object的方法时,传递实参是单个基本数据类型的数组,和传递单个其他类型的数组,方法会有不同的处理方式。
分别说明处理方式:
(1)基本数据类型的数组是Object的子类,当其做为实参传递给方法时,方法会把数组当成一个Object对象,接着把这个Object对象装进一个Object[]数组中,然后再从这个Object[]数组中取出元素使用。可以看出这种处理方式跟不是数组的实参传递进方法中的处理方式是一样的。
(2)其他类型的数组同样是Object的子类,当其作为实参传递给方法时,方法会认为它就是Object[]数组,不会再装进新的Object[]数组中,而是直接从这个Object[]数组中取出元素来使用。
从上面说明可以看出,区别处理的关键点在于,方法是把数组看成是一个Object对象还是一个Objuect[]数组。
基于关键点,我们传递其他类型数组的实参时,如果是希望整个数组作为一个对象来参与方法中运算,可以通过两种方式来实现。
(1)先将其他类型的数组装进一个Object[]数组中(变成二维数组),这样方法接收到实参时,就会把其当成Object[]数组处理,然后直接从这个Object[]数组中取出元素使用,这样即可实现取出的是我们定义的其他类型数组。
(2)把其他类型的数组强转成Object对象(使用(Object)),这样方法接收到实参时,会把实参当成Object对象,装进一个新的Object[]数组中,再从这个数组中取出元素使用,这样即可取出Object对象,也就是我们定义的其他类型数组。
下面是具体例子:
1 class VarArgsTest { 2 3 public static void main(String[] args) { 4 5 // 基本数据类型数组。 6 int[] arr = {1,2,4}; 7 // 字符串数组。 8 String[] arr1 = {"a","b","c"}; 9 Test t = new Test(); 10 t.print(arr); //结果打印int数组的hashCode地址。 11 t.print(arr1); //结果会打印String数组中的每个元素。 12 t.print((Object)(arr1)); //结果会打印String数组的hashCode地址。 13 } 14 } 15 16 class Test { 17 18 // 可变参数类型为Object。 19 void print(Object... args) { 20 for (Object obj : args) { 21 System.out.println(obj); 22 } 23 } 24 }
关于可变参数需要注意的地方整理得差不多了,找资料前还以为是比较简单的东西。结果才发现需要注意的东西有很多,真是学无止境啊......