Java方法重载和varargs

kun*_*ard 6 java overloading compiler-errors variadic-functions ambiguous

我试图理解方法重载,我有这些方法.

public void method(int a){
    System.out.println("int a");
}

//implementing interface method
@Override
public void method() {
    System.out.println("interface");
}

//varargs
public void method(int ... a){
    System.out.println("int ... a");
}
Run Code Online (Sandbox Code Playgroud)

用这些参数调用它们之后,

int[] a = new int[5];
stack.method();
stack.method(1);
stack.method(5,6);
stack.method(null);
stack.method(a);
Run Code Online (Sandbox Code Playgroud)

我有这些结果:

interface
int a
int ... a
int ... a
int ... a

据我所知,该程序不应该编译,因为模糊不清,但无论如何它都可以.编译器不应该抛出错误吗?

T.J*_*der 5

null伊兰和芭丝谢芭已经说过为什么选择了各种不使用的。

剩下的问题是:为什么stack.method(null);还要编译?

答案是它与 varargs 签名匹配,因为method(int...)从编译器的角度来看,varargs 实际上与method(int[]). 由于数组是通过引用来引用的,因此可以在需要nullan 的地方使用。int[]

所以:

stack.method();
Run Code Online (Sandbox Code Playgroud)

method()与界面中的签名完全匹配。没有歧义,method(int...)因为只有当其他参数不匹配时才会考虑可变参数。

stack.method(1);
Run Code Online (Sandbox Code Playgroud)

火柴method(int)。出于与上述相同的原因,没有歧义。

stack.method(5,6);
Run Code Online (Sandbox Code Playgroud)

匹配是method(int...)因为没有一个非可变参数匹配,但可变参数匹配。

stack.method(null);
Run Code Online (Sandbox Code Playgroud)

参见前面的解释。

stack.method(a);
Run Code Online (Sandbox Code Playgroud)

匹配match(int...)原因相同method(null0:因为对于编译器来说match(int...)实际上是相同的。match(int[])


Era*_*ran 4

方法重载解析分为三个阶段。第一和第二阶段不将带有可变参数的方法(也称为变量参数方法)视为候选方法,因此仅当找不到不带可变参数的匹配方法时,编译器才会将带有可变参数的方法视为候选方法。

\n\n

因此,在第一个和第二个方法调用中,yourvoid method(int ... a)被忽略,并且不存在歧义。

\n\n
\n

15.12.2。编译时步骤 2:确定方法签名

\n\n

第二步在上一步中确定的类型中搜索成员方法。此步骤使用方法名称和参数表达式来定位可访问且适用的方法,即可以在给定参数上正确调用的声明。

\n\n

可能有不止一种这样的方法,在这种情况下,选择最具体的一种。最具体方法的描述符(签名加返回类型)是运行时用于执行方法分派的描述符。

\n\n

如果方法适用于严格调用\n (\xc2\xa715.12.2.2)、松散调用 (\xc2\xa715.12.2.3) 或变量参数\n 调用 (\xc2\xa715) 之一,则该方法适用。 .12.2.4)。

\n\n

适用性测试将忽略某些包含隐式类型 lambda\n 表达式 (\xc2\xa715.27.1) 或不精确方法引用 (\xc2\xa715.13.1) 的参数表达式,因为\n 无法确定它们的含义,直到选择目标类型。

\n\n

尽管方法调用可能是多表达式,但只有其参数表达式(而不是调用的目标类型)影响适用方法的选择。

\n\n

确定适用性的过程首先确定\n 可能适用的方法 (\xc2\xa715.12.2.1)。

\n\n

该过程的其余部分分为三个阶段,以确保与 Java SE 5.0 之前的 Java 编程语言版本兼容。这些阶段是:

\n\n
    \n
  1. 第一阶段 (\xc2\xa715.12.2.2) 执行重载解析,不允许装箱或拆箱转换,或使用变量 arity\n 方法调用。如果在此阶段没有找到适用的方法\n,则处理将继续到第二阶段。\n 这保证了在 Java SE 5.0 之前的 Java 编程语言中有效的任何调用都不会被视为不明确\n,因为引入的结果变量数量方法、隐式装箱和/或拆箱。但是,变量 arity 方法 (\xc2\xa78.4.1) 的声明可以更改为给定方法调用表达式选择的方法,因为变量 arity 方法在第一阶段。例如,在已声明 m(Object) 的类中声明 nm(Object...) 会导致某些调用表达式(如 m(null))不再选择 nm(Object),如 m (Object[]) 更具体。

  2. \n
  3. 第二阶段 (\xc2\xa715.12.2.3) 执行重载解析,同时允许装箱和拆箱,但仍然阻止使用变量方法调用。如果在此阶段没有找到适用的方法,则处理将继续到第三阶段。这可确保如果某个方法可通过固定数量方法调用适用,则永远不会通过可变数量方法调用来选择该方法。

  4. \n
  5. 第三阶段(\xc2\xa715.12.2.4)允许重载与可变参数方法相结合允许重载与可变数量方法、装箱和拆箱

  6. \n
\n
\n