バインディングは、メソッド呼び出しと、それが配置されているクラスとの関連付けを指します。
バインディングは、静的バインディングと動的バインディングに分類できます。
静的バインディングと動的バインディングを分析する前に知っておく必要があるいくつかの概念:
コンパイル期間: コンパイル プロセスでは、Java ソース ファイルをバイトコード (.class ファイル、JVM 実行可能コード) にコンパイルします。このプロセスでは、Javaこのプロセスではメモリは処理されません。コンパイラは構文を分析し、構文が間違っている場合はエラーを報告します。
ランタイム: 実行プロセスとは、JVM (Java 仮想マシン) がバイトコード ファイルをロードし、実行のために解釈することを意味します。このプロセスでは、メモリが実際に作成され、Java プログラムが実行されます。
Java でのメソッド呼び出しプロセスは次のとおりです:
エディターは、宣言されたオブジェクトの型とメソッド名を調べます。メソッドのオーバーロードにより呼び出される可能性のあるメソッドの候補をすべて取得します。たとえば、メソッド 1 は print(String str)、メソッド 2 は print(int) です。
コンパイラは、呼び出しメソッドの入力パラメータの型を調べます。候補となる方法からマッチング方法を選択します。たとえば、入力パラメータが「hello」の場合は、print(String str) を選択します。
メソッドがプライベート、静的、最終変更、またはコンストラクターの場合、コンパイラーはどのメソッドを呼び出すかを決定できます。これは静的バインディングです。
これに当てはまらない場合は、ランタイム (動的) バインディングを使用する必要があります。
静的バインディング。早期バインディングおよびコンパイル時バインディングとも呼ばれます。コンパイル時のバインドを示します。つまり、プログラムが実行される前にメソッドがバインドされています。
final、static、および private によって変更されたメソッド、メンバー変数、およびコンストラクターのみが静的にバインドされます:
型 | 説明 |
---|---|
final | それによって変更されたメソッドは継承できますが、オーバーライドすることはできません。サブクラス オブジェクトを呼び出すことはできますが、親クラスで定義されたメソッドが呼び出されます。これは、メソッドを Final として宣言することで書き換えを回避し、動的バインディングをオフにできることを間接的に示します。 |
private | それによって変更されたメソッドには暗黙的にfinalキーワードが含まれています。これは外部からは見えないため、継承したりオーバーライドしたりすることはできません。クラス自体のオブジェクトを通じてのみ呼び出すことができるため、メソッドが実行される前にオブジェクトをクリアできます。 |
static | 静的メソッドはクラスに依存し、オブジェクトに依存します。これはサブクラスによって継承できますが (基本的にサブクラスによって隠蔽されます)、サブクラスによってオーバーライドすることはできません。サブクラス オブジェクトが親クラス オブジェクトに変換されると、サブクラスで静的メソッドが定義されているかどうかに関係なく、オブジェクトは親クラスの静的メソッドを使用します。したがって、ここでは静的メソッドを隠すことができると言われています。 |
メンバー変数 | デフォルトでは、Java はプロパティに静的バインディングを使用するため、コンパイル中にプログラム エラーを見つけることができ、効率が向上します。 |
コンストラクター メソッド | コンストラクター メソッドは、サブクラスが親クラスを継承する場合、デフォルトで最初に親クラスのコンストラクターを (明示的または暗黙的に) 呼び出します。したがって、プログラムを実行する前に、コンストラクター メソッドがどのオブジェクトを参照しているかを知ることができます。 |
次の例を見てください:
// 父类class Parent{ // 变量 String name="Parent"; // 静态方法 static void print(){ System.out.println("Parent print"); } // 私有方法 private void say(){ System.out.println("Parent say"); } // 终态方法 final void look(){ System.out.println("Parent look"); } }// 子类class Son extends Parent{ String name ="Son"; static void print(){ System.out.println("Son print"); } // 编译错误,无法重写父类的 final方法 final void look(){}; }public class Test{ public static void main(String[] args) { // 发生向上转型 Parent p = new Son(); // 输出 Parent System.out.println(p.name); // 输出 Parent print p.print(); // 编译错误,对外不可见 p.say(); } }
動的バインディングは、遅延バインディングとも呼ばれ、実行時バインディングを意味します。
動的バインディングのプロセス:
仮想マシンはオブジェクトの実際のタイプのメソッドテーブルを抽出します。
メソッドシグネチャを検索します。
メソッドを呼び出します。
例を見てみましょう:
class A { int x = 5; } class B extends A { int x = 6; } class Parent { public A getValue() { System.out.print("Parent Method "); return new A(); } } class Son extends Parent { public B getValue() { System.out.print("Son Method "); return new B(); } }public class Test { public static void main(String[] args) { // 向上转型 Parent p = new Son(); // 输出结果:Son Method 5 // 注意:是 5 不是 6 ! System.out.println(p.getValue().x); } }
次のような出力分析を観察してください:
p.getValue()、上方変換により、この時点で最初にサブクラス (Son) からメソッドを探します。 time 呼び出されるメソッドは Son です。これが動的バインディングです。
p.getValue( ).x、x はメンバー変数であるため、そのオブジェクト (親に属する) は、プログラムが実行される前にここで決定されます。
まだ理解できない場合は、別の例を見てみましょう:
class Parent { String name = "Parent " + this.getClass().getName(); } class Son extends Parent { String name = "Son" + this.getClass().getName(); }public class Test { public static void main(String[] args) { // 向上转型 Parent p = new Son(); // 输出:Parent Son System.out.println(p.name); } }
次のような出力分析を観察してください:
p.name: name はメンバー変数であり、この時点で静的バインディングが発生するため、 Parent のプロパティは と呼ばれます。
this.getClass( ): getClass はメソッドです。このとき上方変換が発生するため、デフォルトのプログラムは、たまたまサブクラスにも存在するこのメソッドをサブクラスから検索します。したがって、サブクラスのメソッドが呼び出され、このときに動的バインディングが発生します。
上記は 07.Java Basics - Static Binding & Dynamic Binding の内容です。その他の関連コンテンツについては、PHP 中国語 Web サイト (www.php.cn) に注目してください。