面試系列:為什么不同返回類型不算方法重載?
作者:磊哥
來源 | 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
- }
- }
為什么不同返回類型不算方法重載?
要回答這個問題,首先要了解一點前置內容,方法簽名。方法簽名是由:方法名稱 + 參數類型 + 參數個數組成的一個唯一值,這個唯一值就是方法簽名,而 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 "磊哥聊編程";
- }
- }
像以上情況,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:基本類型自動轉換成更大的基本類型
接下來我們把精準匹配方法刪掉,觀察一下第二匹配順序是什么?實現代碼如下:
- 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... 方法");
- }
- }
以上程序的執行結果如下圖所示:
因此我們可以得出結論:如果是基本數據類型,那么方法重載調用的第二匹配原則是自動轉換成更大的基本數據類型。
匹配原則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... 方法");
- }
- }
以上程序的執行結果如下圖所示:
從上述執行結果可以看出,方法重載的第三匹配原則是,匹配自動裝箱或拆箱的數據類型。
匹配原則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... 方法");
- }
- }
以上程序的執行結果如下圖所示:
從上述執行結果可以看出,方法重載的第四匹配原則是,依次向上匹配父類的方法調用。
匹配原則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... 方法");
- }
- }
以上程序的執行結果如下圖所示:
從上述執行結果可以看出,方法重載的第五匹配原則是,匹配可選參數。
總結
在同一個類中定義了多個同名方法,但每個方法的參數類型或者是參數個數不同就是方法重載。方法重載的典型使用場景是 String 中的 valueOf 方法,它有 9 種實現。方法返回類型不能作為方法重載的依據,因為它不是方法簽名的組成部分。方法重載有 5 個匹配原則:精準匹配、基本類型自動轉換成更大的基本類型匹配、自動裝/拆箱匹配、按照繼承路線依次向上匹配、可變參數匹配。