過載和重寫的編碼區別及JVM編譯區別
一、在程式碼層次過載和重寫的區別如下:
過載:
1、過載的方法間方法名相同,引數的個數及型別不相同,引數及其型別表不相同即可(引數型別的順序不同,引數型別個數及引數個數相同亦可);
2、不能通過訪問許可權、返回值及丟擲異常進行過載;
3、方法的異常型別及數目不會對過載造成影響;
重寫:
1、存在於子類中,是對父類方法的覆蓋;
2、重寫的方法,方法名、引數表個數、型別及順序必須與父類被重寫方法完全一樣;
3、重寫方法的修飾符一定要大於被重寫方法的修飾符:public>protected>default (private 方法無法被子類獲取,不構成重寫);
4、重寫方法的返回值必須與被重寫方法一致;
5、重寫方法不能比被重寫方法的丟擲檢查範圍廣泛的檢查異常,例如被重寫方法的丟擲異常為:IndexOutOfBoundsException,重寫方法的異常不能是:Exception;
6、靜態方法不能被重寫,如果子類存在於父類完全相同的靜態方法,那麼會將父類的此方法隱藏,具體呼叫那個方法,要看宣告;
7、重寫方法增加註解:@Override 後會自動做如上的重寫檢查
(
引用及參考:
http://blog.csdn.net/ycb1689/article/details/17163273;(靜態方法重寫的解析很到位)
http://www.iteye.com/problems/99162;(不完整,參考了此文回答的重寫異常部分)
http://blog.csdn.net/baggio7095586/article/details/6149261(存在錯誤,程式碼層次的區別基於此在驗證後得出的結論。))
二、JVM編譯基礎上的區別:
過載:
1、JVM中對此方法呼叫的解析方法為靜態分派:使用的是invokespecial;
重寫:
1、JVM對重寫的方法的解析為動態分派:使用的是invokevirtual;體現效果為,當父類方法被重寫後,無論宣告和初始化的是子類還是父類,最終處理的都是重寫的方法;
說明如下:
1、方法呼叫的解析
在Class檔案中,方法呼叫是常量池中的一個符號引用,在載入的解析期或者執行時才能確定直接引用。
下面兩種指令是在解析期就可以確定直接引用,呼叫的對應方法也叫作非虛方法。
a、 invokestatic 主要用於呼叫靜態方法
b、 invokespecial 主要用於呼叫私有方法,構造器,父類方法。
下面兩種是在執行時才能確定直接引用的,但是除了final方法,final方法也可以在解析期確定方法的呼叫版本。
a、 invokevirtual 虛方法,不確定呼叫那一個實現類
b、 invokeinterface 介面方法,執行時才能確定實現介面的物件。
2、動態分派
先回顧一下靜態和動態分派的概念。Java中,所有以靜態型別來定位方法執行版本的分派動作,都稱為靜態分派。其實也就是過載(Overload)就是一種典型的靜態分派,在編譯期就可以知道方法呼叫的實際版本。相對得,動態分派是需要在執行期才能確定方法的版本,也就是直接引用,一種典型應用就是重寫(OverWrite)。在呼叫invokevirtual指令時,把常量池中的類方法符號引用解析到直接引用的過程就是重寫的過程,執行期根據實際型別確定方法的執行版本。
3、重寫JVM解析圖:
這個是類被虛擬機器載入進方法區之後,在方法區裡面的佈局。
如果我們像上面那樣,用一個基類引用指向子類物件,那麼,這個引用所繫結的類還是子類。只不過它所能訪問的虛方法表與一般子類物件不同。上面黃色的部分才是父類這個引用所能訪問的vtable的範圍(關於vtable的生成有時間在總結),而普通的子類引用可以訪問整個子類的vtable。
(
引用及參考:
http://yunshen0909.iteye.com/blog/2231374;(此文通過對位元組碼的解讀,清楚的劃分了過載是靜態分派,重寫是動態分派)
http://blog.csdn.net/qc_liu/article/details/42584099;(清晰的解析了重寫的JVM實現邏輯)
)