jvm原理(33)バイトコードによるJava法の静的割り当てと動的割り当てメカニズム(invokevirtual命令)の解析

1899 ワード

コードの作成:
public class MyTest6 {
    public static void main(String[] args) {
        Fruit apple = new Apple();
        Fruit orange = new Orange();
        apple.test();
        orange.test();

        apple = new Orange();
        apple.test();
    }
}

class Fruit{
    public void test(){
        System.out.println("fruit");
    }
}

class Apple extends  Fruit{
    @Override
    public void test() {
        System.out.println("apple");
    }
}

class Orange extends Fruit{
    @Override
    public void test() {
        System.out.println("orange");
    }
}

実行結果:
apple
orange
orange

mainメソッドのバイトコード命令を見てみましょう.
0 new#2//new命令スタック内にオブジェクト3 dup//スタックトップ4 invokespecial#3>//invokespecial命令親を呼び出すコンストラクタ7 astore_を作成1//戻りオブジェクト参照apple 8 new#4 11 dup 12 invokespecial#5>15 astore_2 16 aload_1//ローカル変数から1つの参照aload 1をロードインデックス1の参照(apple)で、ローカル変数は3つ(0:args;1:apple;2:orange)17 invokevirtual#6//invokevirtual命令で、注意パラメータはFruit.testであり、Apple.test 20 aload_ではない2//ロードorange 21 invokevirtual#6//invokevirtualコマンドを呼び出します.パラメータはFruit.testで、orange.test 24 new#4//スタック内にオブジェクト27 dup//スタックトップ28 invokespecial#5>//オブジェクトを呼び出すコンストラクタ31 astore_1//対応する参照をapple 32 aload_に付与1//参照apple 33 invokevirtual#6//invokevirtualコマンドをロードし、参照appleのtestを呼び出します.注意パラメータはFruit.testで、apple.test 36 return//戻ります
OK,ok~~今までこのプログラムのバイトコードレベルではどのように行ったのか分かりましたが、もう一つのinvokevirtualは、バイトコードレベルではFruit.testを指していましたが、実行するときは具体的な事例の方法で、この問題は説明する必要があります.
invokevirtualの実行時にまず、オペランドスタックの一番上の最初の要素がオブジェクトの実際のタイプを指しているのを見つけて、このタイプの中で、それから定数の中でFruitのメソッド記述子とメソッド名が一致するメソッドを探して、このタイプの下で、定数プールの中で見つけたら実際のオブジェクトメソッドの直接参照に戻ります.
見つからない場合は、継承システムに従って下から上へ(Apple->Fruit->Object)検索し、一致を検索する方法は上記の方法で、ビットが見つかるまでです.ずっと見つからないと異常を投げ出す.
メソッドリロード(overload)とメソッド書き換え(overwrite)を比較すると,メソッドリロードは静的であり,コンパイラ挙動であると結論できる.メソッドの書き換えは動的であり,実行期間の動作である.