14

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.

short...为什么和有区别int

4

6 回答 6

19

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

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

编译器首先尝试在没有装箱或拆箱的情况下解析该方法,如引用的那样:

第一阶段(第 15.12.2.2 节)执行重载决议,不允许装箱或拆箱转换,或使用变量 arity 方法调用。如果在此阶段没有找到适用的方法,则处理继续到第二阶段。

强调我的。

因此,在您的一个代码中,因为short可以用作int类型参数的参数。编译器不会使用带有参数的方法Short,因为这需要装箱。而在long类型的情况下,由于它不能用作int类型的参数,因此将其装箱为Long. 请记住,加宽比拳击更受欢迎

在你的第 2 次int除了拳击,别无他法Integer。因此,它调用带有Integer参数的方法。

于 2013-08-01T16:28:14.237 回答
9

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

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

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

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

于 2013-08-01T16:25:58.670 回答
1

因为在 Java 的 1.0 版中向上转换为 int 并且在 5.0 版中添加了自动装箱。更改行为会破坏为旧版本 Java 编写的代码。

于 2013-08-01T16:28:15.817 回答
0

加宽发生在拳击之前(如果有的话)。因此short将成为int并调用该方法。

此外,与这个问题没有直接关系,但有趣的一点是:你不能装箱和加宽,即short不能成为Integer

于 2014-07-08T15:09:42.413 回答
0

下面的视频清楚地解释了 JVM 在方法重载的情况下如何在各种符合条件的方法中选择一种方法。

https://www.youtube.com/watch?v=P4XtP1aeI3g

于 2017-06-08T14:50:00.950 回答
0

Java 首先查找最接近的匹配项。它试图找到以下内容:

  1. 按类型精确匹配
  2. 匹配超类类型
  3. 转换为更大的原始类型
  4. 转换为自动装箱类型
  5. 可变参数
于 2017-04-11T21:25:02.017 回答