Java method invokeの命令概要

4197 ワード

メソッド呼び出しに関連するjvmサブコマンドセットには、主に次の4つがあります.
 
invokestatic---------------------->呼び出しクラスメソッド(静的バインド、速度が速い)
 
invokevirtual----------------------------->インスタンスメソッドの呼び出し(ダイナミックバインド)
 
invokespecial------------------------------------------------------------------インスタンスメソッドを呼び出す(静的バインド、速度が速い)
 
invokeinterface---------------------->呼び出し参照タイプがinterfaceのインスタンスメソッド(ダイナミックバインド)
 
invokedynamic--------------->JDK 7が導入したのは,主に動的言語のメソッド呼び出しをサポートするためである.参照可能
      New JDK 7 Feature: Support for Dynamically Typed Languages in the Java Virtual Machine
 
オペランドオペランド説明
invokestatic indexbyte 1,indexbyte 2 argsをstackからポップアップしconstant poolインデックス指向のインスタンスメソッドを呼び出す
 
invokevirtual indexbyte 1,indexbyte 2 objectrefとargsをstackからポップアップしconstant poolインデックス指向のインスタンスメソッドを呼び出す
 
invokespecial indexbyte 1,indexbyte 2 objectrefとargsをstackからポップアップしconstant poolインデックス指向のインスタンスメソッドを呼び出す
 
invokeinterface indexbyte 1,indexbyte 2 objectrefとargsをstackからポップアップしconstant poolインデックス指向のインスタンスメソッドを呼び出す
 
//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
invokevirtualとinvokespecialの違いは、invokespecialは通常、オブジェクトのクラスではなく、参照のタイプに応じて方法を選択することです.すなわち、動的バインドではなく静的バインドが使用されます.
 
invokespecialコマンドを使用する場合は、次の3つに分けられます.
1.インスタンス初期化方法(())方法
2.プライベートメソッド
3.superキーワード呼び出しを使用する方法
 
 
invokespecial and Private Methods
次の例を見てみましょう.
 
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();
    }
}

 
 Here are the bytecodes for the main() method of class Subclass:
0:   new     #5; //class Subclass
3:   dup
4:   invokespecial   #6; //Method "":()V
7:   astore_1
8:   aload_1
9:   invokevirtual   #7; //Method exampleMethod:()V
12:  return

SubclassはSuperclassからexampleMethod()メソッドを継承しています.SubclassのmeオブジェクトがexampleMethod()を呼び出すとinvokevirtualが使用されます.JVMは新しいスタックフレームを作成してスタックに押し込み、exampleMethod()のbytecodeを実行します.次はexampleMethod()のbytecodeです.
0:   aload_0
1:   invokespecial   #5; //Method interestingMethod:()V
4:   return

exampleMethod()は、まずローカル変数0に割り当てられたreferenceをstackに押し込み(パラメータthisがすべてのインスタンスメソッドに伝達されることを隠す)、invokespecial命令を使用してこの参照を介してinterestingMethod()を呼び出す.
ここのオブジェクトの場合、Subclassのインスタンスであり、SubclassクラスのinterestingMethod()メソッドにもアクセスできますが、JVMは最終的にSuperclassクラスのinterestingMethod()メソッドを呼び出します.
プログラムの正しい出力は「Superclass's interesting method」です.ここで生成されたbytecodeで呼び出されたinterestingMethod()はinvokespecial命令を使用し、invokespecial命令を呼び出すと、JVMはreference typeに従ってchoiceで呼び出されたmethodを使用します.
 
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
呼び出しインタフェース参照メソッドは、呼び出しクラス参照メソッドよりも遅い場合があることが考えられる.JVMがinvokevirtual命令に遭遇すると、インスタンスメソッドのシンボル参照を直接参照として解析するため、生成された直接参照はメソッドテーブルのオフセット量であり、その後も同じオフセット量を使用することができる可能性が高い.しかし、invokeinterfaceコマンドでは、仮想マシンがinvokeinterfaceコマンドに遭遇するたびに、メソッドテーブルを再検索することはできません.仮想マシンは、今回のオフセット量が前回のオフセット量と同じと仮定できないためです.
最も速い命令はinvokespecialとinvokestaticにすぎない.これらの命令は静的にバインドされているからだ.すなわち、コンパイラで決定されているからだ.したがって、JVMがこれらの命令のためにシンボル参照を解析する場合、シンボル参照は直接飲用に変換され、生成された直接参照は実際の操作コードを指すポインタを含む.
 
以上の内容は『Java仮想マシンに深く入り込む』を参照してください.