Javaの静的バインディングと動的バインディング

次のような質問について考えることができます。

JVM はどのクラスのメソッド ソース コードが呼び出されているかをどのようにして知るのでしょうか? ここの裏話は何ですか?

この記事では、 JVM メソッド呼び出しの静的バインディング動的バインディング メカニズム (自動バインディング)を公開します。

これら 2 つのバインディングを理解する前に、まずバインディングという言葉を理解したほうがよいでしょう。

バインディングとは何ですか?

Java におけるバインディングとは、メソッド呼び出しと、そのメソッドが配置されているクラス (メソッド本体) との関連付けを指します。

Java におけるバインディングは、静的バインディングと動的バインディングに分けられ、アーリー バインディングまたはレイト バインディングと呼ばれます。

静的バインディング

メソッドはプログラムが実行される前にバインドされています。Java の場合、これは単にプログラムのコンパイル時のバインドとして理解できます。

この文はどういう意味ですか? つまり、コンパイル時に、メソッドがどのクラスに対応するかがわかります。

Java のメソッドの場合、初期バインドされるのは、final、static、private、およびコンストラクター メソッドのみです。

単純に 2 つのデモを作成できます。

public class Father {
    public static final void f1(){
        System.out.println("Father-f1()");
    }
}
public class StaticCall {
    public static void main(String[] args) {
        Father.f1();
    }
}

単純にバイトコード ファイルを分析してみましょう (ここでは、IDEA がバイトコードを確認するためのプラグイン jclasslib を強くお勧めします)

 対応する最初の行の JVM は、invokespecial を通じて f1() メソッドを定数プールに入れ、その後、Father クラスが配置されているメソッド領域で f1() メソッドの直接アドレスを見つけて、直接アドレス StaticCall クラスの定数プール内の定数テーブルに記録されます。この処理を定数プール解析と呼び、今後再び Father.f1() を呼び出すと、f1 メソッドのバイトコードが直接検索されます。

上記のプロセスにより、定数プールの分析後、JVM は呼び出される f1() メソッドがメモリ内のどこに配置されているかを判断できることがわかりました。実際、この情報はコンパイル段階で StaticCall クラスの定数プールに記録されています。コンパイル段階でどのメソッドを呼び出すかを決定するこの方法は、静的バインディング メカニズムと呼ばれます。

static によって変更された静的メソッドに加えて、private によって変更されたすべてのプライベート メソッドと、final によって変更されたサブクラスによるオーバーライドが禁止されているメソッドは、invokestatic 命令にコンパイルされます。さらに、すべてのクラスの初期化メソッド <init> および <clinit> は、invokespecial 命令にコンパイルされます。JVM は静的バインディング メカニズムを使用して、これらのメソッドをスムーズに呼び出します。

Final: finalメソッドは継承できるが、オーバーライド(カバー)はできない サブクラスオブジェクトの呼び出しは可能だが、親クラスに定義されたfinalメソッドが呼び出される(このことから、メソッドがfinal型として宣言されていることが分かる) 1 つはメソッドが上書きされないようにするため、もう 1 つは Java の動的バインディングを効果的に閉じるためです。

private: private メソッドの場合、まず継承できません。継承できないため、そのサブクラスのオブジェクトを介して呼び出すことはできず、このクラス自体のオブジェクトを介してのみ呼び出すことができます。したがって、プライベート メソッドは、メソッドを定義するクラスにバインドされていると言えます。

動的バインディング

つまり、オブジェクトは実行時にインラインでバインドされます。

具体的なオブジェクトのタイプに基づいて実行時にバインドします。実行時にオブジェクトのタイプを判断し、それぞれ適切なメソッドを呼び出すためのいくつかのメカニズムが提供されています。つまり、この時点ではコンパイラーはまだオブジェクトの型を認識していませんが、メソッド呼び出しメカニズムはそれ自体を調査して、正しいメソッド本体を見つけることができます。

実際、いつ動的バインディングを使用する必要があるのでしょうか? つまり、実行時にオブジェクトをバインドする必要がある場合、継承について考えるのは難しくありません。動的バインディングを作成する必要があります。

サブクラスを使用するときに、サブクラスのメソッドが上書きされると、その時点でメソッド バインディングを変更する必要があるため、これは実際には Java におけるポリモーフィズムの 1 つの方法です。

参考記事:https://blog.csdn.net/zhangjk1993/article/details/24066085

おすすめ

転載: blog.csdn.net/weixin_43918614/article/details/124450025