JVM處理方法調(diào)用與返回(譯)

方法調(diào)用

java程序語言提供了兩種基本方法:實例方法和類(靜態(tài))方法.其不同點是:

  1. 實例方法在調(diào)用前需要一個對象實例,而類方法不需要.
  2. 實例方法使用動態(tài)綁定晴股,而類方法使用靜態(tài)綁定.

JVM用invokevirtualinvokestatic兩種不同的指令來分別處理實例方法和類方法的調(diào)用.

動態(tài)鏈接

符號引用 是一簇唯一標識一個方法,包括類名,方法名产场,和方法描述(方法返回值,參數(shù)類型等)等信息的存放在常量池中的標識.當在運行時舞竿,遇到方法調(diào)用的指令時京景,就會解決符號引用.

為了解決符號引用,JVM定位到被符號引用的標識骗奖,并將其替換成直接引用.直接引用确徙,比如一個指針或一個偏移量靡菇,能夠使虛擬機調(diào)用方法更快(沒有使用過).

驗證

在將符號引用轉(zhuǎn)成直接引用時,JVM會附加執(zhí)行一些驗證檢查操作.這些檢查確保java語言規(guī)則被遵守并且調(diào)用指令能被安全執(zhí)行.比如米愿,虛擬機首先確保符號引用的方法存在.如果存在,虛擬機檢查確保當前類能合法進入到要調(diào)用的方法.比如鼻吮,如果方法是private育苟,它必須是當前類的成員.如果有一個檢查失敗,JVM將拋出異常.

對象引用和參數(shù)問題

在上面準備好了直接引用后椎木,JVM將要準備參數(shù)违柏,實例方法需要有對象引用.這些參數(shù)必須在調(diào)用指令之前必須通過字節(jié)碼指令push到調(diào)用方法(發(fā)起方)的操作數(shù)棧中.

Pushing and poping 棧幀

調(diào)用一個方法時,JVM將為被調(diào)用方法創(chuàng)建一個新的棧幀.棧幀包括方法的本地變量表香椎、操作數(shù)棧和該虛擬機特殊實現(xiàn)需要的其他信息.本地變量表和操作數(shù)棧的大小在編譯時就已經(jīng)計算好了.

當方法調(diào)用時將在棧中增加一個新的棧幀就叫做Pushing一個棧幀.當方法返回時移除一個棧幀叫做poping一個棧幀.

調(diào)用java方法

當調(diào)用一個java方法時漱竖,JVM將push一個新的棧幀到當前的java棧中.

針對一個實例方法,VM 將pops調(diào)用方法棧幀中的對象引用和操作數(shù)棧中的參數(shù).JVM創(chuàng)建一個新的棧幀畜伐,并且將新的棧幀中本地變量的0(this)替換為對象引用馍惹,其他的1、2替換為其他參數(shù).

針對類方法玛界,VM僅僅調(diào)用方法棧幀中的操作數(shù)棧中的參數(shù)万矾,并用他們替換新的棧幀中的本地變量0,1,2....

一旦新的棧幀中的本地變量表替換完成,VM將新的棧幀作為當前棧幀并且設(shè)置程序計數(shù)器指向新方法的第一條指令.

The JVM specification does not require a particular implementation for the Java stack. Frames could be allocated individually from a heap, or they could be taken from contiguous memory, or both. If two frames are contiguous, however, the virtual machine can just overlap them such that the top of the operand stack of one frame forms the bottom of the local variables of the next. In this scheme, the virtual machine need not copy objectref and args from one frame to another, because the two frames overlap. The operand stack word containing objectref in the calling method's frame would be the same memory location as local variable 0 of the new frame

調(diào)用本地方法

如果調(diào)用的方法是本地方法,JVM以一種依賴實現(xiàn)的方法來調(diào)用慎框。VM不會為本地方法向java棧push一個新的棧幀良狈,At the point at which the thread enters the native method, it leaves the Java stack behind. When the native method returns, the Java stack once again will be used.

其他方法調(diào)用形式

盡管實例方法一般通過invokevirtual來調(diào)用,然而invokespecialinvokeinterface這兩個操作碼被用來調(diào)用某種情形的特殊方法.

invokespecial用于基于引用類型的實例化方法.用于三種情形:

  1. 調(diào)用實力初始化(<init>)方法
  2. 調(diào)用私有方法
  3. 調(diào)用使用super關(guān)鍵字的方法

invokeinterface用來調(diào)用一個接口引用的實例方法.

invokespecialinvokevirtual不同點:

invokespecial選擇的方法是基于引用類型而不是對象的類類型.或者說笨枯,是靜態(tài)綁定而不是動態(tài)綁定薪丁。

invokespecial與私有方法

class Superclass {
    private void interestingMethod() {
        System.out.println("Superclass's interesting method.");
    }
    void exampleMethod() {
        interestingMethod();
    }
}
class Subclass extends Superclass {
    void interestingMethod() {
        System.out.println("Subclass's interesting method.");
    }
    public static void main(String args[]) {
        Subclass me = new Subclass();
        me.exampleMethod();
    }
}

以上將打印:

Superclass's interesting method.

由于invokespecial,VM將選擇基于引用類型的方法,所以如此打印.

方法調(diào)用事例

interface inYourFace {
    void interfaceMethod ();
}
class itsABirdItsAPlaneItsSuperClass implements inYourFace {
    itsABirdItsAPlaneItsSuperClass(int i) {
        super();                    // invokespecial (of an <init>)
    }
    static void classMethod() {
    }
    void instanceMethod() {
    }
    final void finalInstanceMethod() {
    }
    public void interfaceMethod() {
    }
}
class subClass extends itsABirdItsAPlaneItsSuperClass {
    subClass() {
        this(0);                    // invokespecial (of an <init>)
    }
    subClass(int i) {
        super(i);                   // invokespecial (of an <init>)
    }
    private void privateMethod() {
    }
    void instanceMethod() {
    }
    final void anotherFinalInstanceMethod() {
    }
    void exampleInstanceMethod() {
        instanceMethod();             // invokevirtual
        super.instanceMethod();       // invokespecial
        privateMethod();              // invokespecial
        finalInstanceMethod();        // invokevirtual
        anotherFinalInstanceMethod(); // invokevirtual
        interfaceMethod();            // invokevirtual
        classMethod();                // invokestatic
    }
}
class unrelatedClass {
    public static void main(String args[]) {
        subClass sc = new subClass(); // invokespecial (of an <init>)
        subClass.classMethod();       // invokestatic
        sc.classMethod();             // invokestatic
        sc.instanceMethod();          // invokevirtual
        sc.finalInstanceMethod();     // invokevirtual
        sc.interfaceMethod();         // invokevirtual
        inYourFace iyf = sc;
        iyf.interfaceMethod();        // invokeinterface
    }
  }

方法返回

JVM會使用針對每一種返回類型的操作來返回.返回值將從操作數(shù)棧pop并且push到調(diào)用方法的方法棧幀中.當前的棧幀pop,被調(diào)用方法的棧幀變成當前的.程序計數(shù)器將重置為調(diào)用這個方法的指令的下一條指令.

操作碼描述:

  1. ireturn none pop int, push onto stack of calling method and return

  2. lreturn none pop long, push onto stack of calling method and return

  3. freturn none pop float, push onto stack of calling method and return

  4. dreturn none pop double, push onto stack of calling method and return

  5. areturn none pop object reference, push onto stack of calling method and return

  6. return none return void

    The ireturn instruction is used for methods that return int, char, byte, or short.

結(jié)論

  1. 實例方法是動態(tài)綁定的,除了<init>馅精、private和super關(guān)鍵字調(diào)用的方法,這三種特殊情況严嗜,實例方法是靜態(tài)綁定的.
  2. 類方法是靜態(tài)綁定的.
  3. 與接口引用相關(guān)的實例方法可能比同樣的對象關(guān)聯(lián)的方法慢.

參考鏈接

how the java virtual machine handles method invocation and return

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市洲敢,隨后出現(xiàn)的幾起案子阻问,更是在濱河造成了極大的恐慌,老刑警劉巖沦疾,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件称近,死亡現(xiàn)場離奇詭異,居然都是意外死亡哮塞,警方通過查閱死者的電腦和手機刨秆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來忆畅,“玉大人衡未,你說我怎么就攤上這事。” “怎么了缓醋?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵如失,是天一觀的道長。 經(jīng)常有香客問我送粱,道長褪贵,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任抗俄,我火速辦了婚禮脆丁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘动雹。我一直安慰自己槽卫,他們只是感情好,可當我...
    茶點故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布胰蝠。 她就那樣靜靜地躺著歼培,像睡著了一般。 火紅的嫁衣襯著肌膚如雪茸塞。 梳的紋絲不亂的頭發(fā)上丐怯,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天,我揣著相機與錄音翔横,去河邊找鬼读跷。 笑死,一個胖子當著我的面吹牛禾唁,可吹牛的內(nèi)容都是我干的效览。 我是一名探鬼主播,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼荡短,長吁一口氣:“原來是場噩夢啊……” “哼丐枉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起掘托,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤瘦锹,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后闪盔,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體弯院,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年泪掀,在試婚紗的時候發(fā)現(xiàn)自己被綠了听绳。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡异赫,死狀恐怖椅挣,靈堂內(nèi)的尸體忽然破棺而出头岔,到底是詐尸還是另有隱情,我是刑警寧澤鼠证,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布峡竣,位于F島的核電站,受9級特大地震影響量九,放射性物質(zhì)發(fā)生泄漏适掰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一娩鹉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧稚伍,春花似錦弯予、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至垦搬,卻和暖如春呼寸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背猴贰。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工对雪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人米绕。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓瑟捣,卻偏偏與公主長得像,于是被迫代替她去往敵國和親栅干。 傳聞我的和親對象是個殘疾皇子迈套,可洞房花燭夜當晚...
    茶點故事閱讀 44,652評論 2 354

推薦閱讀更多精彩內(nèi)容