Java の静的バインディングと動的バインディング
プログラム バインディングの概念:
バインディングは、メソッド呼び出しと、メソッドが配置されているクラス (メソッド本体) の関連付けを指します。 Java の場合、バインディングは静的バインディングと動的バインディング、または初期バインディングと遅延バインディングに分けられます。コンパイル プロセスでは、このメソッドがどのクラスにあるかはすでにわかっており、この時点でコンパイラまたは他のリンカによって実装されます。例: C.
Java の場合、これは単にプログラムのコンパイル中のバインディングとして理解できます。ここで特別な注意事項があります。Java では、final、static、private、およびコンストラクター メソッドのみが事前にバインドされます
遅延バインディング: 実行時の特定のオブジェクトのタイプに基づいたバインディング。
言語が遅延バインディングを実装する場合、実行時にオブジェクトの型を決定し、それぞれ適切なメソッドを呼び出す何らかのメカニズムも提供する必要があります。つまり、この時点ではコンパイラはまだオブジェクトの型を認識していませんが、メソッド呼び出しメカニズムはそれ自体で調査して、正しいメソッド本体を見つけることができます。言語が異なれば遅延バインディングの実装方法も異なります。しかし、少なくとも次のように考えることができます。それらはすべて、何らかの特別な種類の情報をオブジェクトに配置する必要があるということです。
動的バインディングのプロセス:
仮想マシンはオブジェクトの実際の型のメソッドテーブルを抽出します。
privateメソッドに関しては、まず継承できないので、経由で呼び出す方法がありません。そのサブクラスのオブジェクトであり、このクラス自体のオブジェクトを通じてのみ呼び出すことができます。したがって、プライベート メソッドは、このメソッドを定義するクラスにバインドされていると言えます。
コンストラクターは継承できません(インターネット上では、サブクラスは親クラスのパラメーターなしのコンストラクターを独自のコンストラクターとして無条件に継承するとも言われていますが、サブクラスが super() Call を使用していることがわかっているため、この記述は個人的には適切ではないと考えています親クラスのパラメータなしのコンストラクターを使用して親クラスの初期化を完了する必要はありません。したがって、サブクラスが親クラスのコンストラクターを継承するとは言えません。そのため、コンパイルすることができます。また、このコンストラクターがどのクラスに属しているかもわかります。
Java の実行プロセスとは、バイトコード ファイルをロードし、実行のために解釈する jvm (Java 仮想マシン) を指します。このプロセスでは、実際にメモリレイアウトが作成され、Java プログラムが実行されます。
Java バイトコードを実行するには 2 つの方法があります: (1) ジャストインタイム コンパイル方式: インタプリタがまずバイトをマシン コードにコンパイルし、次にマシン コードを実行します。 (2) インタープリタ実行方式: インタプリタが各インタープリタを渡します。そして、小さなコードを実行して、Java バイトコード プログラムのすべての操作を完了します。 (ここでは、Java プログラムが実行中に実際に 2 回変換されることがわかります。最初はバイトコードに、次にマシンコードにです。これが、Java を 1 回コンパイルすればどこでも実行できる理由です。対応する Java 仮想マシンをインストールすることで、異なるプラットフォーム上でも同じバイトコードは、異なるプラットフォームで実行できるように、異なるプラットフォーム上のマシンコードに変換できます)
前に述べたように、Java のメソッドについては、final を除き、事前にバインドされている静的メソッド、プライベートメソッド、およびコンストラクターメソッドを除き、その他すべてのメソッドを除きます。メソッドは動的にバインドされます。
動的バインディングは通常、親クラスとサブクラスの変換宣言の下で発生します:
例: Parent p = new Children();
具体的なプロセスの詳細は次のとおりです:
1: コンパイラチェック 宣言された型およびオブジェクトのメソッド名。
x.f(args) メソッドを呼び出し、x がクラス C のオブジェクトとして宣言されているとします。コンパイラーは、クラス C 内の f という名前のメソッドと、クラス C メソッドのスーパークラスから継承された f という名前のメソッドをすべて列挙します。
2: 次に、コンパイラーはメソッド呼び出しで提供されたパラメーターの型をチェックします。
f という名前のすべてのメソッドの中に、呼び出しによって提供されたパラメーターの型に最も一致するパラメーターの型が存在する場合、このメソッドが呼び出されます。このプロセスは「オーバーロード解決」と呼ばれます。
3: プログラムの実行中に動的バインディングを使用してメソッドが呼び出される場合、仮想マシンは、x が指すオブジェクトの実際の型と一致するバージョンのメソッドを呼び出す必要があります。
実際の型が D (C のサブクラス) であると仮定します。クラス D が f(String) を定義している場合、このメソッドが呼び出されます。それ以外の場合、メソッド f(String) は D のスーパークラスで検索されます。の上。
JAVA 仮想マシンがクラス メソッド (静的メソッド) を呼び出すとき、オブジェクト参照のタイプ (通常はコンパイル時に判明) に基づいて呼び出されるメソッドが選択されます。逆に、仮想マシンがインスタンス メソッドを呼び出すときは、オブジェクトの実際の型 (実行時にのみ知ることができます) に基づいて呼び出されるメソッドが選択されます。これは、ポリモーフィズムの一種である動的バインディングです。 。動的バインディングは、実際のビジネス上の問題を解決するための優れた柔軟性を提供し、非常に美しいメカニズムです。
メソッドとは異なり、Java クラスでメンバー変数 (インスタンス変数とクラス変数) を扱う場合、実行時バインディングは使用されませんが、一般的な意味での静的バインディングが使用されます。したがって、上向き変換の場合、オブジェクトのメソッドはサブクラスを見つけることができますが、オブジェクトの属性 (メンバー変数) は依然として親クラスの属性です (サブクラスは親クラスのメンバー変数を隠します)。
public class Father { protected String name = "父亲属性"; } public class Son extends Father { protected String name = "儿子属性"; public static void main(String[] args) { Father sample = new Son(); System.out.println("调用的属性:" + sample.name); } }
結論、呼ばれたメンバーは父親の属性です。
この結果は、サブクラスのオブジェクト(親クラスからの参照ハンドル)が親クラスのメンバ変数を呼び出していることを示しています。したがって、ランタイム (動的) バインディングの範囲はオブジェクトのメソッドのみであることを明確にする必要があります。
今、サブクラスのメンバー変数名を呼び出そうとしているのですが、どうすればよいでしょうか?最も簡単な方法は、メンバー変数をゲッター メソッドにカプセル化することです。
コードは次のとおりです:
public class Father { protected String name = "父亲属性"; public String getName() { return name; } } public class Son extends Father { protected String name = "儿子属性"; public String getName() { return name; } public static void main(String[] args) { Father sample = new Son(); System.out.println("调用的属性:" + sample.getName()); } }
結果: プロパティの静的バインディング メソッドのため、息子のプロパティは
Java と呼ばれます。これは、静的バインディングには、実行時ではなくコンパイル時にプログラム内のエラーを検出できるため、多くの利点があります。これにより、プログラムの実行効率が向上します。
以上がJavaの静的バインディングと動的バインディングのサンプルコードの詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。