動的割り当て方法の書き換え

3679 ワード

前に書く
以前は静的配分を知っていましたが、今は動的配分(良い専門の概念、以前は私も知らなかった)を見ています.動的配分という専門名詞は知りませんでしたが、書き直し(Override)は、使ったことがあるに違いありません.
コード推定結果
public class DynamicTest {
    static abstract class Car{
         protected abstract void driveCar();

    }

    static class Train extends Car{

        @Override
        protected void driveCar() {
            System.out.println("I am driving train");

        }

    }

    static class Bus extends Car{

        @Override
        protected void driveCar() {
            System.out.println("I am driving bus");

        }

    }

    public static void main(String[] args) {
        Car train = new Train();
        Car bus = new Bus();
        train.driveCar();
        bus.driveCar();
    }
}

結果表示
I am driving train
I am driving bus

この運行結果、私も推測しました.最終的に実行するときは具体的なサブクラスオブジェクトを指すが,これ以上深いレベルでは答えられない.
分析プロセス
Car train = new Train();
Car bus = new Bus();

コードが実行されるとき、trainとbusが指すタイプは何なのかを明らかにする必要があります.一つは静的タイプ(Car)、もう一つは実際のタイプ(TrainまたはBus)です.上記の結果から,それらは実際のタイプを指していることが明らかになった.静的タイプによって決定されなくなると、コンパイル期間で作成された指定ではないに違いありません.次に、このクラスを逆コンパイルして、真相を探ります.
  public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=3, args_size=1
         0: new           #2                  // class com/erayt/DynamicTest$Tra
in
         3: dup
         4: invokespecial #3                  // Method com/erayt/DynamicTest$Tr
ain."":()V
         7: astore_1
         8: new           #4                  // class com/erayt/DynamicTest$Bus

        11: dup
        12: invokespecial #5                  // Method com/erayt/DynamicTest$Bu
s."":()V
        15: astore_2
        16: aload_1
        17: invokevirtual #6                  // Method com/erayt/DynamicTest$Ca
r.driveCar:()V
        20: aload_2
        21: invokevirtual #6                  // Method com/erayt/DynamicTest$Ca
r.driveCar:()V
        24: return
      LineNumberTable:
        line 30: 0
        line 31: 8
        line 32: 16
        line 33: 20
        line 34: 24
}

dup:スタックトップ数値をコピーし、スタックトップにコピー値を押し込むinvokespecial:スーパークラス構築メソッド、インスタンス初期化メソッド、プライベートメソッドastore_を呼び出す1:スタックトップ参照値を最初のローカル変数astore_に格納2:スタックトップリファレンス値を2番目のローカル変数aload_に格納1:2番目の参照タイプのローカル変数をスタックトップaload_にプッシュ2:3番目の参照タイプのローカル変数をスタックトップにプッシュ
invokevirtual:インスタンスメソッドの呼び出し
逆コンパイルから見ると、0-15行で行うことは、trainとbusのメモリ領域を確立し、TrainとBusタイプのインスタンスコンストラクタを呼び出し、この2つのインスタンスをローカル変数テーブルの1、2番目のslotスロットに参照して格納することです.対応するコードは,上の2つのnewオブジェクトのプロセスである.
次に、作成したばかりの2つのオブジェクトの参照を、driveCar()メソッドを実行する所有者である16と20の2つのオブジェクトのスタックの上部に押し当てます.17と21の2つのオブジェクトはメソッド呼び出しコマンドですが、この2つのコマンドが最終的に実行されるターゲットメソッドではだめです.invokevirtualコマンドのマルチステート検索プロセスについてお話しします.実行時にどのように解析されますか.
invokevirtual命令のマルチステート検索プロセス
1.オペランドスタックの一番目の要素が指す実際のタイプを見つけます(上の16と20の2つの文は、作成したばかりの2つのオブジェクトの参照をスタックの一番に押します).
2.この実際のタイプで定数の記述記号と簡単な名前が一致する方法が見つかった場合、権限チェックを行い、通過するとこの方法の直接参照を返し、検索が終了し、通過せず、エラーを報告し、javaを返す.lang.IllegalAccessError異常
3.この実タイプで定数の記述記号と単純な名前が一致する方法が見つからない場合は、継承関係に従って実タイプの各親を上から下へ順に2ステップ目の検索と検証を行います.
4.常に適切な方法が見つからない場合は、エラーjavaを投げ出す.lang.AbstractMethodError異常
最後に書く
この実行期間の多態性の検索はinvokevirtual命令が機能していたが、最初のステップは実行期間に受信者の実際のタイプを決定することである.上の逆コンパイルの17と21文はinvokevirtual命令を呼び出して定数プールの中のクラス方法の記号参照を異なる直接参照上に解析した(クラスのロード過程を思い出して、ロード、検証、準備、解析、初期化)、上の逆コンパイルの17文の中からinvokevirtual命令の後ろのパラメータも、この定数がCarであることを示した.driveCar()のシンボル参照.
17: invokevirtual #6   // Method com/erayt/DynamicTest$Car.driveCar:()V

このプロシージャもjava書き換えの本質であり,実行期間が実際のタイプに基づいてメソッド実行バージョンを決定する割り当てプロシージャを動的割り当てと呼ぶ.