JVM 如何在函数重载的情况下找到要调用的方法(具有最接近匹配的参数)

2022-09-03 18:16:28

JVM 决定在编译时调用哪个重载方法。我有一个例子:

public class MainClass{

  public static void go(Long n) {System.out.println("takes Long ");}
  public static void go(Short n) {System.out.println("takes Short ");}
  public static void go(int n) {System.out.println("takes int ");}

  public static void main(String [] args) {
    short y = 6;
    long z = 7;
    go(y);
    go(z);
    go((Short)y);
  }
}

根据我的理解,它应该打印以下内容:

takes Short
takes Long
takes Short

...但实际输出为:

takes int
takes Long
takes Short

但是,如果我有以下三个功能:

public static void go(Integer n) {System.out.println("takes Integer");}
public static void go(Long n) {System.out.println("takes Long ");}
public static void go(Short n) {System.out.println("takes Short ");}

...并使用以下方式调用它:

int a= 10; and go(i);  //output : takes Integer.

...为什么 和 有区别?shortint


答案 1

请参阅 JLS 第 15.12.2 节,了解编译器遵循的规则,以确定要调用的方法。编译器总是选择最具体的方法,以防您的方法重载:

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

编译器首先尝试在不装箱或取消装箱的情况下解析该方法,如下面引用:

第一阶段 (§15.12.2.2) 执行重载解析,不允许装箱或取消装箱转换,也不允许使用可变 arity 方法调用。如果在此阶段找不到适用的方法,则处理将继续到第二阶段。

强调我的。

因此,在您的第 1代码中,因为 short 可以用作 int 类型参数的参数。编译器不会使用带有参数的方法,因为这需要装箱。而在类型的情况下,由于它不能用作类型int的参数,因此它用于将其装箱到。请记住,加宽比拳击更可取ShortLong

在你的2nd中,除了拳击到.com之外,没有其他方法。因此,它使用参数调用方法。intIntegerInteger


答案 2

JVM根本没有找到它。编译器可以。它选择最具体的方法,遵循 JLS 第 15.12.2.5 节中的规则

如果多个成员方法既可访问又适用于方法调用,则需要选择一个成员方法来为运行时方法调度提供描述符。Java 编程语言使用选择最具体方法的规则。

非正式的直觉是,如果第一个方法处理的任何调用都可以传递给另一个方法而不会出现编译时类型错误,则一种方法比另一个方法更具体。

...(完整规则)...