java 重载 不可_深入深刻深到不能再深的理解java中的重载和重写
面向?qū)ο蟮娜齻€特性
面向?qū)ο笥腥齻€重要的特性:多態(tài),繼承,封裝。
多態(tài)的表現(xiàn)
多態(tài)的在java中的應(yīng)用體現(xiàn)在方法的重載和重寫。
重載:字面上的意義一個類里面,有同名但是參數(shù)必須不相同的方法。(這里的”不同參數(shù)“必須不是泛型,比如List 和List)
重寫:對應(yīng)的是子類去重寫了父類的方法,有自己的實現(xiàn),不能更改方法的參數(shù)和名稱。
但是在JVM中是怎么實現(xiàn)的呢?JVM對于這兩種方式是怎么區(qū)分的?
方法的重載
我們都知道,.java的源文件都會被編譯成.class的文件,class文件是一堆二進(jìn)制流。
執(zhí)行 方法的指令在JVM里面有四個
invokestatic 執(zhí)行靜態(tài)的方法
invokespecial 執(zhí)行構(gòu)造方法,或者調(diào)用父類的方法(對應(yīng)super關(guān)鍵字)
invokedynamic 執(zhí)行動態(tài)語言的方法
invokevirtual 執(zhí)行普通方法
考慮下面代碼
class A{
pulic void print(B b){
}
pulic void print(C c){
}
}
public static void main(String args[]){
A a = new A();
B b = new C();
a.print(b);
}
當(dāng)我們調(diào)用 a.print(b)的時候,虛擬機會根據(jù)你傳遞參數(shù)的靜態(tài)類型去匹配方法,這是一個靜態(tài)分派的過程。
什么叫靜態(tài)類型 比如 B b = new C();C是派生B的,我們經(jīng)常在java中這么寫,沒有任何問題。這里對象B的靜態(tài)類型就是B,但是它的實際類型是C。
我們調(diào)用a.print(b)的時候它匹配的是 print(B b)這個方法,所以編譯器它不會考慮這個b的實際類型(因為B的實際類型會被執(zhí)行invospecial去指定)是什么,它直接在編譯成字節(jié)碼階段就把這個方法匹配了。
它的字節(jié)碼
image.png
但是還有一個點要注意,靜態(tài)類型是可以強轉(zhuǎn)的
public static void main(String args[]){
A a = new A();
B b = new C();
a.print((C)b);
}
這時候它匹配的就是print(C c)這個方法了
image.png
方法重載:只會根據(jù)參數(shù)的靜態(tài)類型去匹配。
方法的重寫
方法的重寫:表現(xiàn)的就是重寫父類的方法
public class B {
public void callMe(){
System.out.print("B is call");
}
}
public class C extends B {
@Override
public void callMe() {
System.out.print("C is call");
}
}
public static void main(String args[]){
B b = new B();
b.callMe();
B c = new C();
c.callMe();
}
在編譯階段它只會在靜態(tài)類型中去匹配方法,所以盡管b和c 的實際類型不同,但它們執(zhí)行callMe的字節(jié)碼指令是相同的
image.png
但是虛擬機在執(zhí)行這個指令的時候,它會先在操作數(shù)棧中拿到調(diào)用這個方法的對象,然后根據(jù)這個對象的實際類型去匹配方法,如果這個類型里面沒有,則它就會去父類去找一直遞歸直到找到為止。否則將會拋出MethodNotFoundException。
這樣遞歸非常麻煩,所以虛擬機會對每一個clas對象都生成一個方法表。(這個在連接階段會準(zhǔn)備好,一般再類變量初始為零值之后)
它里面保存了這個類所有方法直接引用(也是就能再虛擬機中找到執(zhí)行的代碼),保存的順序先是父類的方法,然后才是自己的方法,如果子類重寫了父類的方法,它會將這個指針指向自己的實現(xiàn),否則指向父類,這樣的好處是只用查找一次,不管類型怎么切換,只要他們的方法表的順序是一致的,我就可以根據(jù)這個下標(biāo)去找到對應(yīng)的方法入口。
image.png
比如使用son的對象 son.hardChoice(),會再son的方法表里面找到方法入口,虛擬機會記住這個下標(biāo),當(dāng)我再使用
father.hardChoice()的時候,直接切換到Father的方法表,通過記住的這個下標(biāo)找到方法入口,不用去遍歷了!
同理接口也有對應(yīng)的接口表,它里面的方法就是無序的了,無法通過下標(biāo)去查找,每一次調(diào)用方法都只能去遍歷整個表,所以一般來說查找接口方法比查找普通方法要慢。
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的java 重载 不可_深入深刻深到不能再深的理解java中的重载和重写的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: IC卡复位应答ATR的数据元和它们的意义
- 下一篇: java内存高水位_jvm(1)---j