📅  最后修改于: 2020-03-31 06:18:40             🧑  作者: Mango
Varargs中的方法重载
重载允许不同的方法具有相同的名称,但签名不同,其中签名可能因输入参数的数量或输入参数的类型或两者而不同。我们可以通过采用可变长度参数的方式重载:
情况1 :仅具有Varargs参数的方法,在这种情况下,Java使用类型差异来确定要调用的重载方法。如果一个方法签名比另一个方法签名更具体,则Java选择它时不会出现错误。
//Java展示使用varargs进行重载
public class varargsDemo
{
public static void main(String[] args)
{
fun();
}
//varargs方法,float数据类型
static void fun(float... x)
{
System.out.println("float varargs");
}
//varargs方法,int数据类型
static void fun(int... x)
{
System.out.println("int varargs");
}
//varargs方法,double数据类型
static void fun(double... x)
{
System.out.println("double varargs");
}
}
输出:
int varargs
此输出是由于int比double更具体。如JLS第15.12.2.5节中的规定,如可以访问多个成员方法并将其应用于方法调用,则必须选择一个成员方法来提供运行时方法分派的描述符。Java编程语言使用类型提升选择最具体方法的规则。在这种情况下,以下规则定义了原始类型之间的直接超类型关系:
情况2 : 带有Varargs以及其他参数的方法在这种情况下,Java使用参数的数量和参数的类型来确定要调用的方法。
下面是重载fun()方法三次的Java程序:
// Java展示Varargs重载
class Test
{
// 一个方法,使用varargs(integers).
static void fun(int ... a)
{
System.out.print("fun(int ...): " +
"参数的数量: " + a.length +
" 计数: ");
// 使用for each循环来打印a的内容
for(int x : a)
System.out.print(x + " ");
System.out.println();
}
// 一个方法,使用varargs(booleans).
static void fun(boolean ... a)
{
System.out.print("fun(boolean ...) " +
"参数的数量: " + a.length +
" 内容: ");
// 用for each循环来打印a的内容
for(boolean x : a)
System.out.print(x + " ");
System.out.println();
}
// 一个方法,使用varargs(string和integers).
static void fun(String msg, int ... a)
{
System.out.print("fun(String, int ...): " +
msg + a.length +
" 内容: ");
// 用for each循环来打印a的内容
for(int x : a)
System.out.print(x + " ");
System.out.println();
}
public static void main(String args[])
{
// 用不同的参数调用重载之后的fun()
fun(1, 2, 3);
fun("测试: ", 10, 20);
fun(true, false, false);
}
}
输出:
fun(int ...): 参数的数量: 3 内容: 1 2 3
fun(String, int ...): 测试: 2 内容: 10 20
fun(boolean ...) 参数的数量: 3 内容: true false false
Varargs和歧义
重载带有可变长度参数的方法时,有时会导致意外错误。这些错误涉及歧义,因为这两种方法都是调用的有效候选者。编译器无法决定将哪个方法绑定到该方法调用。
// Java Varargs和歧义
class Test
{
// 一个方法使用varargs(integers).
static void fun(int ... a)
{
System.out.print("fun(int ...): " +
"参数数量: " + a.length +
" 内容: ");
// 使用for each循环打印a
for(int x : a)
System.out.print(x + " ");
System.out.println();
}
// 一个方法使用varargs(booleans).
static void fun(boolean ... a)
{
System.out.print("fun(boolean ...) " +
"参数的数量: " + a.length +
" 内容那个: ");
// 使用 for each打印a
for(boolean x : a)
System.out.print(x + " ");
System.out.println();
}
public static void main(String args[])
{
// 调用重载的fun()
fun(1, 2, 3); //合法
fun(true, false, false); //合法
fun(); // 错误: 歧义!!
}
}
在上面的程序中,fun()的重载是完全正确的。但是,由于以下调用,该程序将无法编译:
fun(); // 错误: 歧义!
根据(JLS 15.2.2),有3个阶段用于重载解析:第一阶段执行解析而不允许装箱或拆箱转换;第二阶段执行重载解析,同时允许装箱和拆箱;第三阶段允许重载与变量组合arity方法,装箱和拆箱。如果在这些阶段未找到适用的方法,则会产生歧义。
上面的调用可以转换为对fun(int…)或fun(boolean…)的调用。两者同等有效,并且在重载解析的所有三个阶段之后都无法解析,因为两种数据类型都不同。因此,该调用本质上是模棱两可的。
歧义的另一个示例:
fun()的以下重载版本本质上是模棱两可的:
static void fun(int ... a) { // 方法体 }
static void fun(int n, int ... a) { //方法体 }
在这里,尽管fun()的参数列表有所不同,但是编译器无法解决以下调用:
fun(1)
此调用可能解析为fun(int…a)或fun(int n,int…a)方法,从而造成歧义。为了解决上述类似的歧义错误,我们将需要放弃重载,而仅使用两个不同的方法名称。