深圳幻海软件技术有限公司 欢迎您!

面试系列:为什么不同返回类型不算方法重载?

2023-02-28

作者:磊哥来源|Java面试真题解析(ID:aimianshi666)转载请联系授权(微信ID:GG_Stone)面试合集:https://gitee.com/mydb/interview方法重载是指在同一个类中,定义了多个同名方法,但每个方法的参数类型或者是参数个数不同就是方法重载。比如以下4个m

作者:磊哥

来源 | Java面试真题解析(ID:aimianshi666)

转载请联系授权(微信ID:GG_Stone)

面试合集:https://gitee.com/mydb/interview

方法重载是指在同一个类中,定义了多个同名方法,但每个方法的参数类型或者是参数个数不同就是方法重载。比如以下 4 个 method 方法就可以称之为方法重载,如下代码所示:

public class OverloadExample { 
    public void method() { 
        // doSomething 
    } 
 
    public void method(String name) { 
        // doSomething 
    } 
 
    public void method(Integer id) { 
        // doSomething 
    } 
 
    public void method(Integer id, String name) { 
        // doSomething 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

为什么不同返回类型不算方法重载?

要回答这个问题,首先要了解一点前置内容,方法签名。方法签名是由:方法名称 + 参数类型 + 参数个数组成的一个唯一值,这个唯一值就是方法签名,而 JVM(Java 虚拟机)就是通过这个方法签名来决定调用哪个方法的。从方法签名的组成规则我们可以看出,方法的返回类型不是方法签名的组成部分,所以当同一个类中出现了多个方法名和参数相同,但返回值类型不同的方法时,JVM 就没办法通过方法签名来判断到底要调用哪个方法了,如下图所示:

那为什么返回类型不能做为方法签名的一部分呢?原因其实很简单,试想一下,如果方法的返回类型也作为方法签名的一部分,那么当程序员写了一个代码去调用“重载”的方法时,JVM 就不能分辨要调用哪个方法了,如下代码所示:

public class OverloadExample { 
    public static void main(String[] args) { 
        OverloadExample example = new OverloadExample(); 
        example.method("磊哥"); // JVM 应该调用哪个方法? 
    } 
 
    public int method(String name) { 
        // doSomething 
        return 666; 
    } 
 
    public String method(String name) { 
        // doSomething 
        return "磊哥聊编程"
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

像以上情况,JVM 就推断不出来要调用哪个方法了,所以方法的返回类型不能作为方法签名的一部分。

方法重载的使用场景

方法重载的经典使用场景是 String 类型的 valueOf 方法,valueOf 方法重载有 9 种实现,如下图所示:

它可以将数组、对象和基础数据类型转换成字符串类型。

方法重载匹配原则

方法重载的调用顺序是有前后之分的,比如以下代码:

public class OverloadExample { 
    public static void main(String[] args) { 
        OverloadExample example = new OverloadExample(); 
        example.method(12); 
    } 
 
    public void method(int num) { 
        System.out.println("调用 int 方法"); 
    } 
 
    public void method(long num) { 
        System.out.println("调用 long 方法"); 
    } 
 
    public void method(Integer num) { 
        System.out.println("调用 Integer 方法"); 
    } 
 
    public void method(Object num) {  
        System.out.println("调用 Object 方法"); 
    } 
 
    public void method(int... num) { // 可选参数 
        System.out.println("调用 int... 方法"); 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.

当出现方法重载时,程序要调用哪个方法呢?执行以上程序的执行结果如下:

因此我们可以得出以下结论。

匹配原则1:精准类型匹配

方法重载会优先调用和方法参数类型一模一样的方法,这是第一优先匹配原则:精准类型匹配。

匹配原则2:基本类型自动转换成更大的基本类型

接下来我们把精准匹配方法删掉,观察一下第二匹配顺序是什么?实现代码如下:

public class OverloadExample { 
    public static void main(String[] args) { 
        OverloadExample example = new OverloadExample(); 
        example.method(12); 
    } 
 
    public void method(long num) { 
        System.out.println("调用 long 方法"); 
    } 
 
    public void method(Integer num) { 
        System.out.println("调用 Integer 方法"); 
    } 
 
    public void method(Object num) {  
        System.out.println("调用 Object 方法"); 
    } 
 
    public void method(int... num) { // 可选参数 
        System.out.println("调用 int... 方法"); 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.

以上程序的执行结果如下图所示:

因此我们可以得出结论:如果是基本数据类型,那么方法重载调用的第二匹配原则是自动转换成更大的基本数据类型。

匹配原则3:自动装/拆箱匹配

接下来将第二匹配原则中的 long 方法也删除掉,实现代码如下:

public class OverloadExample { 
    public static void main(String[] args) { 
        OverloadExample example = new OverloadExample(); 
        example.method(12); 
    } 
 
    public void method(Integer num) { 
        System.out.println("调用 Integer 方法"); 
    } 
 
    public void method(Object num) { 
        System.out.println("调用 Object 方法"); 
    } 
 
    public void method(int... num) { // 可选参数 
        System.out.println("调用 int... 方法"); 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

以上程序的执行结果如下图所示:

从上述执行结果可以看出,方法重载的第三匹配原则是,匹配自动装箱或拆箱的数据类型。

匹配原则4:按照继承路线依次向上匹配

此时将第三匹配原则中的 Integer 方法删除,剩下代码如下:

public class OverloadExample { 
    public static void main(String[] args) { 
        OverloadExample example = new OverloadExample(); 
        example.method(12); 
    } 
 
    public void method(Object num) { 
        System.out.println("调用 Object 方法"); 
    } 
 
    public void method(int... num) { // 可选参数 
        System.out.println("调用 int... 方法"); 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

以上程序的执行结果如下图所示:

从上述执行结果可以看出,方法重载的第四匹配原则是,依次向上匹配父类的方法调用。

匹配原则5:可变参数匹配

最后将代码中的方法删除的只剩一个可选参数,实现代码如下:

public class OverloadExample { 
    public static void main(String[] args) { 
        OverloadExample example = new OverloadExample(); 
        example.method(12); 
    } 
 
    public void method(int... num) { // 可选参数 
        System.out.println("调用 int... 方法"); 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

以上程序的执行结果如下图所示:

从上述执行结果可以看出,方法重载的第五匹配原则是,匹配可选参数。

总结

在同一个类中定义了多个同名方法,但每个方法的参数类型或者是参数个数不同就是方法重载。方法重载的典型使用场景是 String 中的 valueOf 方法,它有 9 种实现。方法返回类型不能作为方法重载的依据,因为它不是方法签名的组成部分。方法重载有 5 个匹配原则:精准匹配、基本类型自动转换成更大的基本类型匹配、自动装/拆箱匹配、按照继承路线依次向上匹配、可变参数匹配。