從字節(jié)碼分析java的方法重寫和重載

不知道有沒有小伙伴在面試時被問到過方法重寫(Override)和重載(Overload)的區(qū)別?反正我是被問起過數(shù)次佳镜,大概情況是這樣的:

面試官:說下Override和Overload的區(qū)別奥喻?
:(內(nèi)心:額明也,送人頭的选浑,然后就)方法重寫發(fā)生在子畜份、父繼承的關(guān)系下办素,子類可以修改父類的方法角雷,以達到增強、擴展等~~#¥%@ bala bala
面試官:嗯性穿,還有嗎勺三?
:(xx 一緊,還有啥需曾?努力回想是不是忘說了啥)額吗坚,就這些吧
面試官:恩,今天面試就到這吧呆万,你回去等消息吧
:#¥%
@~

方法重寫和重載商源,相信只要是剛接觸過java語言,對這兩個概念就不會陌生谋减,遇到相關(guān)的面試題估計也不少牡彻,今天我們就從面試題下手缎除,然后再分析到其字節(jié)碼層面总寻,對這兩個概念做一個介紹。
首先貼上面試題

// 父類
public class Parent {
    int age = 40;
    public void walk() {
        System.out.println("parent walk");
    }
}

// 子類
public class Child extends Parent {
    int age = 15;
    public void walk() {
        System.out.println("child walk");
    }
}

// 測試重載
public class TestOverload {

    public void method(Parent parent) {
        System.out.println("parent");
    }

    public void method(Child child) {
        System.out.println("child");
    }

    public static void main(String[] args) {
        TestOverload testOverload = new TestOverload();

        Parent parent = new Child();
        testOverload.method(parent);
        Child child = new Child();
        testOverload.method(child);
    }
}

相信機智如你,早就知道了答案衰倦,結(jié)果:

parent
child

Process finished with exit code 0

不多解釋概念,先javap看下字節(jié)碼(為節(jié)省篇幅,只貼出部分常量池和main字節(jié)碼)

Constant pool:
   #1 = Methodref          #12.#34        // java/lang/Object."<init>":()V
   #2 = Fieldref           #35.#36        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = String             #22            // parent
   #4 = Methodref          #37.#38        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #5 = String             #25            // child
   #6 = Class              #39            // com/jvm/learnjvm/test/TestOverload
   #7 = Methodref          #6.#34         // com/jvm/learnjvm/test/TestOverload."<init>":()V
   #8 = Class              #40            // com/jvm/learnjvm/test/Child
   #9 = Methodref          #8.#34         // com/jvm/learnjvm/test/Child."<init>":()V
  #10 = Methodref          #6.#41         // com/jvm/learnjvm/test/TestOverload.method:(Lcom/jvm/learnjvm/test/Parent;)V
  #11 = Methodref          #6.#42         // com/jvm/learnjvm/test/TestOverload.method:(Lcom/jvm/learnjvm/test/Child;)V
  #12 = Class              #43            // java/lang/Object
  #13 = Utf8               <init>


 public static void main(java.lang.String[]);  // main 方法
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=4, args_size=1
         0: new           #6                  // class com/jvm/learnjvm/test/TestOverload
         3: dup
         4: invokespecial #7                  // Method "<init>":()V
         7: astore_1
         8: new           #8                  // class com/jvm/learnjvm/test/Child
        11: dup
        12: invokespecial #9                  // Method com/jvm/learnjvm/test/Child."<init>":()V
        15: astore_2
        16: aload_1
        17: aload_2
        18: invokevirtual #10                 // Method method:(Lcom/jvm/learnjvm/test/Parent;)V
        21: new           #8                  // class com/jvm/learnjvm/test/Child
        24: dup
        25: invokespecial #9                  // Method com/jvm/learnjvm/test/Child."<init>":()V
        28: astore_3
        29: aload_1
        30: aload_3
        31: invokevirtual #11                 // Method method:(Lcom/jvm/learnjvm/test/Child;)V


我們重點看一下main方法的 18: invokevirtual #1031: invokevirtual #11,執(zhí)行的方法肥隆,對照常量池的#10 = Methodref #6.#41 // com/jvm/learnjvm/test/TestOverload.method:(Lcom/jvm/learnjvm/test/Parent;)V,
#11 = Methodref #6.#42 // com/jvm/learnjvm/test/TestOverload.method:(Lcom/jvm/learnjvm/test/Child;)V句各,通過方法入?yún)⒎停梢钥吹胶芮宄目吹秸{(diào)用的方法情況,因為此時并沒有運行绪杏,不知道將來傳入的參數(shù)真實實例是什么,編譯器只是根據(jù)聲明的參數(shù)的類型和數(shù)量等匹配到合適的重載方法僧著,這種方式,被稱為“靜態(tài)分派”皆怕。
同樣在編譯期確定的還有調(diào)用成員變量的經(jīng)典面試題岂津,有興趣的可以自己看下字節(jié)碼分析下

public class TestOverload {

    public void method(Parent parent) {
        System.out.println("parent");
    }

    public void method(Child child) {
        System.out.println("child");
    }

    public static void main(String[] args) {
        TestOverload testOverload = new TestOverload();

        Parent parent = new Child();
        System.out.println(parent.age);
        
        Child child = new Child();
        System.out.println(child.age);
    }
}

結(jié)果

40
15

Process finished with exit code 0

分析完方法重載粱甫,現(xiàn)在分析下方法重寫粉洼,先來一段大家都熟到不能再熟的代碼(Parent和Child類依舊使用之前的)

public class TestOverride {

    public static void main(String[] args) {
        Parent parent = new Child();
        parent.walk();
    }
}

大家用腳指頭想都知道的結(jié)果

child walk

Process finished with exit code 0

面對感覺理所應(yīng)當?shù)慕Y(jié)果,我們還是先看看字節(jié)碼吧

Constant pool:
   #1 = Methodref          #6.#22         // java/lang/Object."<init>":()V
   #2 = Class              #23            // com/jvm/learnjvm/test/Child
   #3 = Methodref          #2.#22         // com/jvm/learnjvm/test/Child."<init>":()V
   #4 = Methodref          #24.#25        // com/jvm/learnjvm/test/Parent.walk:()V
   #5 = Class              #26            // com/jvm/learnjvm/test/TestOverride
   #6 = Class              #27            // java/lang/Object

 public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: new           #2                  // class com/jvm/learnjvm/test/Child
         3: dup
         4: invokespecial #3                  // Method com/jvm/learnjvm/test/Child."<init>":()V
         7: astore_1
         8: aload_1
         9: invokevirtual #4                  // Method com/jvm/learnjvm/test/Parent.walk:()V
        12: return

執(zhí)行方法調(diào)用的是9: invokevirtual #4拙泽,指向的是常量池#4,然后我們絲毫不慌的去常量看看荷荤,
#4 = Methodref #24.#25 // com/jvm/learnjvm/test/Parent.walk:()V
what退渗??会油?調(diào)用的是Parent的walk() 古毛?氣氛突然有些尷尬......
其實這個時候体斩,就要說下面向?qū)ο蟮娜筇匦裕悍庋b蹬敲、繼承瘪校、多態(tài)中的多態(tài)的實現(xiàn)原理了。多態(tài)是什么不用我說大家也都知道名段,就不解釋概念了阱扬,從字節(jié)碼角度說一下,還是回到main方法的字節(jié)碼再看一下信夫,前面主要是創(chuàng)建對象窃蹋,執(zhí)行構(gòu)造方法卡啰,并把當前創(chuàng)建的對象實例壓到操作數(shù)棧,重點看下9警没,執(zhí)行invokevirtual指令匈辱,(jdk提供了5條方法調(diào)用的指令,在最下面有列出),invokevirtual指令是找到當前操作數(shù)棧棧頂元素指向的對象的實際類型杀迹,也就是new出來的Child梅誓,然后執(zhí)行該指令對應(yīng)的常量池中的方法#4,而這時候是運行期佛南,jvm會根據(jù)方法的名稱和描述來定位方法梗掰,調(diào)用的是Child實例的walk,這種動態(tài)調(diào)用方法的方式嗅回,也被稱為動態(tài)分派及穗。

方法調(diào)用指令
invokestatic ?? ??????調(diào)用靜態(tài)方法
invokevirtual ???????調(diào)用實例方法
invokespecial????????調(diào)用私有方法、實例構(gòu)造方法绵载、super()
invokeinterface ????調(diào)用引用類型為interface的實例方法
invokedynamic ???????JDK 7引入的埂陆,主要是為了支持動態(tài)語言的方法調(diào)用,如Lambda

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末娃豹,一起剝皮案震驚了整個濱河市焚虱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌懂版,老刑警劉巖鹃栽,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異躯畴,居然都是意外死亡民鼓,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門蓬抄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來丰嘉,“玉大人,你說我怎么就攤上這事嚷缭∫鳎” “怎么了?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵阅爽,是天一觀的道長路幸。 經(jīng)常有香客問我,道長优床,這世上最難降的妖魔是什么劝赔? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮胆敞,結(jié)果婚禮上着帽,老公的妹妹穿的比我還像新娘。我一直安慰自己移层,他們只是感情好仍翰,可當我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著观话,像睡著了一般予借。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上频蛔,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天灵迫,我揣著相機與錄音,去河邊找鬼晦溪。 笑死瀑粥,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的三圆。 我是一名探鬼主播狞换,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼舟肉!你這毒婦竟也來了修噪?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤路媚,失蹤者是張志新(化名)和其女友劉穎黄琼,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體整慎,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡适荣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了院领。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弛矛。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖比然,靈堂內(nèi)的尸體忽然破棺而出丈氓,到底是詐尸還是另有隱情,我是刑警寧澤强法,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布万俗,位于F島的核電站,受9級特大地震影響饮怯,放射性物質(zhì)發(fā)生泄漏闰歪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一蓖墅、第九天 我趴在偏房一處隱蔽的房頂上張望库倘。 院中可真熱鬧临扮,春花似錦、人聲如沸教翩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽饱亿。三九已至蚜退,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間彪笼,已是汗流浹背钻注。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留配猫,地道東北人幅恋。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像章姓,于是被迫代替她去往敵國和親佳遣。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,955評論 2 355