声明:
本文为牛旦教育原创,头条首发,所有权保留,转载请注明来源。
Java编程中,常遇到一个术语"var-args",这是"可变长度参数"的缩写。 它可以让你声明一个接受可变数量参数的方法或构造函数。 本文中我只使用术语"方法"。 但是,讨论也适用于构造函数。
一个方法接受的参数个数称为参数数量。 接受可变长度参数数量的方法称为可变方法或var-args方法。 var-args方法是什么样的? 在查看var-args方法之前,先讨论非var-args方法的工作原理。
考虑以下用于声明max()方法的MathUtil类的代码。 该方法有两个参数。 它计算并返回它的两个参数的最大值。
public class MathUtil { public static int max(int x, int y) { int max = x; if (y > max) { max = y; } return max; } }
MathUtil类和其max()方法没有什么特别的。 假设你想计算两个整数的最大值,比如12和18,你可以按如下方式调用max()方法:
int max = MathUtil.max(12, 18);
当这个语句执行时,18将被赋值给变量max。 假设你想计算三个整数的最大值。 你可能会想出以下逻辑:
int max = MathUtil.max(MathUtil.max(70, 9), 30);
这个逻辑工作很好。 它计算两个整数的最大值,然后计算两者中最大值和第三个整数的最大值。 假设你想计算最多十个整数。 你可能会重复这个逻辑,并且可以工作,尽管代码可能不可读。 你需要一个更好的方式来做到这一点。
现在尝试重载max()方法,因此它接受三个整数参数。 这是MathUtil类的新版本,称为MathUtil2:
public class MathUtil2 { public static int max(int x, int y) { int max = x; if (y > max) { max = y; } return max; } public static int max(int x, int y, int z) { int max = x; if (y > max) { max = y; } if (z > max) { max = z; } return max; } }
您可以按如下方式求出两个和三个整数的最大值:
int max1 = MathUtil2.max(12, 18);int max2 = MathUtil2.max(10, 8, 18);
添加一个三各int参数的max()方法暂时解决了这个问题。 真正的问题仍然存在。 您必须添加一个max()方法,其中包含所有可能数量的整数参数。 你肯定赞成没有那个程序员想写这么一个max()方法,还得必须不断添加更新的版本。
在Java中引入var-args方法之前,如果在设计时不知道方法的参数个数,则可以将方法参数声明为int数组,如下所示。
public class MathUtil3 {public static int max(int[] num) { /* 必须在此检查num的0个元素情况*/int max = Integer.MIN_VALUE;for(int i = 0; i < num.length; i++) { if (num[i] > max) { max = num[i]; }}return max;}}
您可以编写以下代码片断,使用MathUtil3.max()方法计算两个和三个整数的最大值:
int[] num1 = new int[] {10, 1};int max1 = MathUtil3.max(num1);int[] num2 = new int[] {10, 8, 18} ;int max2 = MathUtil3.max(num2);
可以将任意数量的整数传递给MathUtil3.max()方法。 从某种意义上说,你有办法将任意数量的参数传递给一个方法。 当它的参数类型是一个数组时,该方法需要被调用的方式会让程序员困扰。 也就是,当需要使用数组参数调用该方法时,您必须创建一个数组对象并打包其所有元素的值。 这里的问题不是max(int[] num)方法中的代码; 相反,它是调用此方法的客户端代码——。
对于上述问题,可用Var-args来拯救(解决这个问题)。 让我们声明一个max()方法,它可以接受任意数量的整数参数,包括零参数。 var-args方法的优点在于可用更简单的客户端代码调用该方法。 那么,你如何声明一个var-args方法? 所有要做的就是在方法参数的数据类型之后添加一个省略号(或三连点...)。 以下代码片段显示了一个max()方法声明,其中包含一个可变长度参数num,它是int数据类型。 请注意数据类型为int后的省略号的位置。
public static int max(int... num) {// 在此编写代码}
在省略号之前和之后添加空格是可选的。 以下所有var-args方法声明都是有效的。 它们在省略号之前和之后使用不同类型的空白。
public static int max(int... num) // 省略号后空格public static int max(int ... num) // 前后都有空格public static int max(int...num) // 前后无空格public static int max(int ...num) // 前空格后换行
一个var-args方法可以有多个参数。 以下代码片段显示aMethod()接受三个参数,其中一个参数是可变长度参数:
public static int aMethod(String str, double d1, int...num) {// Code goes here}
注意,var-args方法有两个限制:
- var-args方法最多可以有一个可变长度参数。
以下对m1()方法的声明无效,因为它声明了两个可变长度参数n1和n2;
// 无效声明void m1(String str, int...n1, int...n2) { // 代码...}
- var-args方法的变长参数必须是参数列表中的最后一个参数。
下面的m2()方法的声明是无效的,因为变长参数n1没有被声明为最后一个参数。
// 无效声明void m2(int...n1, String str) {// Code ...}
通过把第一个参数n1移动最后可修正上面的方法声明:
// 有效声明void m2(String str, int...n1) { // Code }
让我们重写max()方法,使其成为一个var-args方法,如下所示:
public class MathUtil4 { public static int max(int...num) { int max = Integer.MIN_VALUE; for(int i = 0; i < num.length; i++) { if (num[i] > max) { max = num[i]; } } return max; }}
几乎总是在var-args方法内部有一个循环,用于处理可变长度参数的参数列表。 length属性给出了为可变长度参数传递的值的数量。 例如,max()变参方法中的num.length将为您提供传递给该方法的整数数量。 要获取变长参数中的第n个值,需要使用varArgsName[n-1]。 例如,num[0], num[1]和num[n-1] 将包含为num可变长度参数传入的第一个,第二个和第n个值。 如果你只是想处理所有传入的变长参数的值,你可以使用一个更简单的循环,一个foreach循环。 可以使用foreach循环重写max()方法的代码,如下所示:
public static int max2(int...num) { int max = Integer.MIN_VALUE; for(int currentNumber : num) { if (currentNumber > max) { max = currentNumber; } } return max; }
MathUtil4.max()方法的主体与将num参数声明为int数组的方法貌似相同。 你如此想是对的。 Java编译器使用数组实现可变长度参数。 MathUtil4.max()方法的前一个声明由编译器更改。 编译代码时,声明部分max(int ... num)被更改为max(int[] num)。 你使用可变长度参数有什么好处? 在方法中使用可变长度参数的好处来自调用方法的优雅方式。 可以按如下方式调用MathUtil4.max()方法(可以看做为包装后的语法糖):
int max1 = MathUtil4.max(12, 8);int max2 = MathUtil4.max(10, 1, 30);
可以在方法中为可变长度参数使用零个或多个参数。 以下代码是对max()方法的有效调用:
int max = MathUtil4.max(); // 无参数也是可行的
通过调用没有参数的MathUtil4.max()方法返回什么? 如果您查看方法的主体,它将返回Integer.MIN_VALUE,即-2147483648。 实际上,不带有至少两个参数的max()方法调用不是有效的调用。 当方法是var-args方法时,必须检查无效的参数数量。 对于非var-args方法,您不会遇到无效参数数量的问题,因为编译器会强制您使用确切数量的参数。 以下max()方法的声明将强制其调用者传递至少两个整数:
// 参数n1 和 n2 是必须的public static int max(int n1, int n2, int... num) { // Code ...}
编译器会将前两个参数n1和n2视为必需参数,将第三个参数num视为可选参数。 现在,您可以将两个或多个整数传递给max()方法。下面清单显示了max()方法的最终完整代码。
清单.使用Var-Args方法计算某些指定整数的最大值的工具类:
// MathUtil5.javapackage com.newday.util;public class MathUtil5 { public static int max(int n1, int n2, int... num) { // 把n1和n2中最大值赋给max int max = (n1 > n2 ? n1 : n2); for(int i = 0; i < num.length; i++) { if (num[i] > max) { max = num[i]; } } return max; } public static void main(String[] args) { System.out.println("max(7, 9) = " + MathUtil5.max(7, 9)); System.out.println("max(70, 19, 30) = " + MathUtil5.max(70, 19, 30)); System.out.println("max(-7, -1, 3) = " + MathUtil5.max(-70, -1, 3)); }}
运行程序的结果如下:
max(7, 9) = 9
max(70, 19, 30) = 70
max(-7, -1, 3) = 3
当您调用MathUtil5.max()方法时,您可以传递任意数量的整数。 以下所有声明均有效:
int max1 = MathUtil5.max(12, 8); // 把12赋给 max1int max2 = MathUtil5.max(10, 1, 30); // 把30赋给 max2int max3 = MathUtil5.max(11, 3, 7, 37); // 把37赋给max3
如果您调用没有参数或一个参数的MathUtil5.max()方法,编译器将会生成一个错误。
int max1 = MathUtil5.max(); // 编译错误int max2 = MathUtil5.max(10); // 编译错误
除了上面的内容,还有两点非常重要:
1).重载Var-Args方法(变参方法)
方法的相同重载规则也适用于var-args方法。 只要方法的参数在类型、顺序或数字上不同,就可重载变长参数方法。 例如,以下是一个重载的max()方法的有效示例:
public class MathUtil6 { public static int max(int x, int y) { // 代码 } public static int max(int...num) { // 代码 } }
考虑以下代码片段,它使用两个参数调用重载方法MathUtil6.max():
int max = MathUtil6.max(12, 13); // 会调用哪个max() ?
MathUtil6类有两个max()方法。 一个方法接受两个int参数,另一个接受一个可变长度的int参数。 在这种情况下,Java将调用max(int x, int y)。Java首先尝试使用完全匹配的参数数量来查找方法声明。 如果它找不到完全匹配,则使用可变长度参数查找匹配。
▶ 提示:
如果var-args方法被重载,Java将使用该方法的更具体的版本,而不是使用var-args方法。Java使用var-args方法作为解决方法调用的最后手段。
有时调用重载的var-args方法可能会导致Java编译器混淆。 方法本身的重载可能是有效的, 但是,对它的调用可能会导致问题。 考虑MathUtil7类的以下代码片段,它是方法重载的有效示例:
public class MathUtil7 { public static int max(int...num) { // Code ... } public static int max(double...num) { // Code ... } }
执行以下语句时将调用哪个版本的max()方法?
int max = MathUtil7.max(); // Which max() to call?
上面的语句会产生一个编译时错误,指出对MathUtil7.max()的调用是不明确的。 Java允许你为可变长度参数传递零个或多个值。 在前面的语句中,max(int ... num)和max(double ... num)两个方法都有资格用于MathUtil7.max()调用。编译器无法决定调用哪一个。 你可能会发现许多其他实例,其中对重载的var-args方法的调用导致模糊的方法调用,编译器将生成一个错误。错误消息将导向有冲突或说有问题的代码。
2).Var-args方法和main()方法
回想一下以前,如果你想运行一个类,你需要声明(或说定义)一个带String数组作为参数的main()方法,且main()方法的签名必须是main(String[] args)。 var-args方法由编译器使用数组来实现。 如果您的方法签名是m1(Xxx…args),则编译器会将其更改为m1(Xxx[] args)。 现在,您可以使用使用String数组的较旧表示法或使用使用var-args的较新表示法来声明类的main()方法。 以下对Test类的main()方法的声明是有效的。 可以使用java命令运行Test类。
public class Test { public static void main(String...args) { System.out.println("Hello from varargs main()..."); } }
以上就是关于Java方法中的可变参数的所有内容,通过本文的介绍,你再也不怕方法的可变参数问题了。
好了,点个赞分享出去吧 ^_^