類與介面(四)方法過載解析

2021-08-16 02:16:06 字數 4751 閱讀 4456

###一、方法過載簡介

方法過載: 當兩個(或多個)方法的名稱相同,而引數的對應型別或個數不同時,我們就說方法過載了。當然,編譯器也能識別出來。

編譯器是如何識別呼叫了哪個方法?

在往下講前,我們先來了解一下:編譯器是怎麼才能識別出程式呼叫了那個方法。其實,這個問題就是在問:在呼叫方法處,編譯器能得到呼叫方法的什麼資訊,從而能找到對應的方法?我們一般的方法呼叫是這樣的:

method( vars );
也就是說,方法呼叫處,一共為編譯器提供兩個資訊:方法名、引數列表。

所以,編譯器只能通過 方法名 和 引數列表 來識別呼叫方法

有一道面試題問:為什麼不能通過返回型別來過載方法?

就是上面所說的,方法呼叫處並沒有提供返回型別的資訊,所以當多個方法只有返回型別不一樣時,編譯器就不知道呼叫了那個方法了。

我們已經知道了編譯器是怎麼識別方法的了,而對於方法過載,其要求方法名是一樣的,那麼我們只需要關注 引數列表 便可以了引數列表區分,或者說過載方法的區分:

###二、方法過載的匹配選擇

方法過載後,方法呼叫處可能會遇到應該選擇哪個過載方法的問題,如果只有唯一個過載方法可以匹配,那麼就沒問題。然而,大部分情況卻是有多個過載方法是可以匹配的,那麼這時候就應該選擇最合適的過載方法.

匹配最合適、最明確的過載方法,其實就是實參列表去匹配當前過載方法中形參列表,尋找與實參列表最相近的形參列表

##1、基本型別之間的過載

對於基本型別來說,從「短型別」擴充套件成「長型別」是預設允許、自動進行的,這就可能造成了實參可能匹配到多個「長型別」的形參,看個簡單例子:

public static void main(string args) 

public static void m(int x)

public static void m(float x)

執行結果

過載方法一

short型別 可以預設自動轉換成int、'float』型別。但m(s)真正匹配選擇的是m(int x)方法,而不是形參長度更長的m(float x)。所以可以看出,基本型別的形參匹配規則是:如果沒有匹配到精確型別的形參,則優先匹配 儲存長度(範圍)大於且是最接近實參的儲存長度的形參,從而確定呼叫哪個過載方法

##2、引用型別間的過載

對於引用型別來說,可以匹配到多個過載方法的原因是:引用型別的物件進行型別上轉也是jvm預設自動進行的,那麼就可能匹配多個祖先型別的形參看下面的例子:

public class test_3    

public static void somemethod(ancestor an)

public static void somemethod(parent an)

}//3個具有繼承關係的類

class ancestor

class parent extends ancestor

class children extends parent

執行結果

this is parent method!

可以看出,引用型別與基本型別一樣,都是選擇」最明確的方法「, 引用型別間選擇最明確的過載方法的規則是: 如果找不到過載方法的形參的引用型別與實參一致,則實參優先匹配 在繼承樹結構上,離實參型別最近的形參,則此形參所在的過載方法便是最明確的過載方法。

##3、自動裝箱拆箱、可變引數型別

裝箱拆箱、以及可變引數列表的處理都是由編譯器自動處理,也就是說是預設自動進行的,這同樣會讓實參列表可以匹配多個形參列表 ,可以匹配多個過載方法

此小節將會涉及到基本型別、引用型別、自動裝箱拆箱可變引數的過載方法匹配的優先順序。

看下面的例子,這個例子包括很多情況:

public class test_3    

public static void overloadmethod(int a)

public static void overloadmethod(short in)

public static void overloadmethod(int a,int b)

public static void overloadmethod(short... s)

public static void overloadmethod(integer... i)

}

執行結果

呼叫 overloadmethod(int)

呼叫 overloadmethod(int)

呼叫 overloadmethod(int,int)

我們來分析一下上面的例子中,方法呼叫處可以匹配到的方法:

檢視輸出結果,發現:test1處選擇了m1、test2選擇了m1,test3選擇了m3。

根據這樣的結果,也就是這幾種形參匹配規則還是有個匹配的順序的。對過載方法的選擇作以下總結:

將上面的總結再簡化一下,可以簡化成過載方法的形參匹配規則的優先順序:

當前型別(基本型別或引用型別)的匹配規則 > 自動裝箱拆箱 > 可變引數列表

再看乙個例子:

public class mytest 

public static void m(int a,short b)

public static void m(float f,short s)

}

執行結果

呼叫了m(float,short)

分析: 實參都是基本型別,優先考慮形參列表都是基本型別的過載方法,找不到才考慮自動裝箱拆箱

##4、泛型方法的過載

泛型方法的過載規則: 將泛型方法的型別變數擦除,然後與非泛型方法一樣,按照上面所說的三種規則一一匹配

public static void main(string args)   };

//呼叫泛型方法

m(r);

}public static void m(t t)

public static void m(t t)

執行結果

呼叫了 void m(t t)

上面的兩個泛型方法m(t t)進行型別擦除後是:

public static void m(object t);

public static void m(runnable t);

顯然,呼叫方法應該是m2,與執行結果相符;

##5. 沒法確定的過載方法呼叫

儘管編譯器會按照上面所說的三種優先級別去讓實參匹配形參,然而匹配的結果卻不一定是唯一的,也就是說會匹配到多個方法,從而無法確定呼叫那個方法,編譯失敗

情況一: 實參列表的所有最佳匹配的形參不在同乙個方法中

public class mytest 

public static void m(int a,double b)

public static void m(float f,int c)

}

分析

m(aa,ss)的呼叫編譯失敗,因為實參aa的最佳匹配m(int,double)的第乙個形參,而實參ss的最佳匹配則是m(float,short)的第二個形參。

因此,實參列表的(aa,ss)的最佳形參型別匹配分開在了兩個過載方法中。

注意一下,即使某個過載方法的形參列表包含最多的最相近的形參型別,只要不是全部,那麼依舊無法確定呼叫了哪個過載方法。

情況二可變引數列表的特殊性 – 無法根據可變引數的型別來過載方法

public static void m(short... s) {}

public static void m(short... s) {}

public static void m(int... s) {}

呼叫測試例子:

short s = 8;

short sl = 10;

m(s,s);//編譯不通過

m(s,sl);//編譯不通過

m(sl,sl);//編譯不通過

##重寫 與 過載的區別

物件導向(四)方法過載

本節目標 掌握方法過載的定義及使用 課程匯入 public void run public void run 那為什麼我們上一小節中可以定義多個構造方法呢?無參構造方法 public dog 帶參構造方法 兩個引數 public dog string name,string 帶參構造方法 publi...

Ruby入門之四(方法)

在ruby中隨意輸出字串,我們可以定義乙個方法。irb main 001 0 def a irb main 002 1 puts hello world irb main 003 1 end nil上面的 中第一行 def a 表示定義了乙個名叫a的方法,是方法定義的開始。下面一行是方法體 puts...

類與物件(二)方法與過載

類中建的方法分為有參的方法和無參的方法倆種 簡單來說就是呼叫的時候可以找到不同的方法,例如 我們new乙個物件 demo d new demo d.showinfo 1 接下來我們說一下傳遞引數,用乙個例子說明 這題的輸出結果是什麼?這題的答案是8 19 為什麼呢?這裡我們講一下基本資料型別和引用資...