###一、方法過載簡介
方法過載: 當兩個(或多個)方法的名稱相同,而引數的對應型別或個數不同時,我們就說方法過載了。當然,編譯器也能識別出來。
編譯器是如何識別呼叫了哪個方法?在往下講前,我們先來了解一下:編譯器是怎麼才能識別出程式呼叫了那個方法。其實,這個問題就是在問:在呼叫方法處,編譯器能得到呼叫方法的什麼資訊,從而能找到對應的方法?我們一般的方法呼叫是這樣的:
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 為什麼呢?這裡我們講一下基本資料型別和引用資...