Java プログラムの実行には、コンパイルと実行 (解釈) の 2 つのステップが必要です。同時に、Java はオブジェクト指向プログラミング言語です。サブクラスと親クラスが同じメソッドを持ち、サブクラスが親クラスのメソッドをオーバーライドする場合、プログラムが実行時にメソッドを呼び出すとき、親クラスのメソッドを呼び出す必要がありますか、それともサブクラスのオーバーライドされたメソッドを呼び出す必要がありますか? Java を初めて学習するときに遭遇する問題は次のとおりです。ここではまず、どのメソッドを呼び出すか、または変数の操作をバインディングと呼ぶかを決定します。
Java には 2 つのバインディング メソッドがあり、1 つは静的バインディングであり、早期バインディングとも呼ばれます。もう 1 つは動的バインディングであり、遅延バインディングとも呼ばれます。
違いの比較
1. 静的バインディングはコンパイル時に発生し、動的バインディングは実行時に発生します
2. private、static、またはfinalで変更された変数またはメソッドには静的バインディングを使用します。仮想メソッド (サブクラスによってオーバーライドできるメソッド) は、ランタイム オブジェクトに基づいて動的にバインドされます。
3. 静的バインディングはクラス情報を使用して完了しますが、動的バインディングはオブジェクト情報を使用して完了する必要があります。
4. オーバーロードされたメソッドは静的バインディングを使用して完成され、オーバーライド メソッドは動的バインディングを使用して完成されます。
オーバーロードされたメソッドの例
オーバーロードされたメソッドの例を次に示します。
public class TestMain { public static void main(String[] args) { String str = new String(); Caller caller = new Caller(); caller.call(str); } static class Caller { public void call(Object obj) { System.out.println("an Object instance in Caller"); } public void call(String str) { System.out.println("a String instance in in Caller"); } } }
の実行結果は
22:19 $ java TestMain a String instance in in Caller
です。 上記のコードには、call メソッドの 2 つのオーバーロードされた実装があり、1 つは Object 型のオブジェクトをパラメーターとして受け取り、もう 1 つは String 型のオブジェクトをパラメーターとして受け取ります。 str は String オブジェクトであり、String 型パラメータを受け取るすべての call メソッドが呼び出されます。ここでのバインディングは、コンパイル時のパラメーターの型に基づく静的バインディングです。
検証
外観を見るだけでは静的にバインドされていることを証明することはできません。javap を使用してコンパイルすることで検証できます。
22:19 $ javap -c TestMain Compiled from "TestMain.java" public class TestMain { public TestMain(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: new #2 // class java/lang/String 3: dup 4: invokespecial #3 // Method java/lang/String."<init>":()V 7: astore_1 8: new #4 // class TestMain$Caller 11: dup 12: invokespecial #5 // Method TestMain$Caller."<init>":()V 15: astore_2 16: aload_2 17: aload_1 18: invokevirtual #6 // Method TestMain$Caller.call:(Ljava/lang/String;)V 21: return }
はこの行 18 を確認しました: invokevirtual #6 // Method TestMain$Caller.call:(Ljava/lang/String;)V は実際に静的にバインドされており、 String オブジェクトをパラメーターとして受け取る呼び出し側メソッドが呼び出されていることが確認されています。
メソッドのオーバーライド例
public class TestMain { public static void main(String[] args) { String str = new String(); Caller caller = new SubCaller(); caller.call(str); } static class Caller { public void call(String str) { System.out.println("a String instance in Caller"); } } static class SubCaller extends Caller { @Override public void call(String str) { System.out.println("a String instance in SubCaller"); } } }
実行結果は
22:27 $ java TestMain a String instance in SubCaller
上記のコードでは、Callerにcallメソッドの実装があり、SubCallerはCallerを継承してcallメソッドの実装を書き換えています。 Caller 型の変数 callerSub を宣言しましたが、この変数は SubCaller オブジェクトを指します。結果によれば、Callerのcallメソッドではなく、SubCallerのcallメソッド実装を呼び出していることがわかります。この結果が生じる理由は、動的バインディングが実行時に発生し、バインド プロセス中にどのバージョンの呼び出しメソッド実装を呼び出すかを決定する必要があるためです。
検証
動的バインディングはjavapを使用して直接検証することはできず、静的バインディングが実行されていないことが証明された場合、動的バインディングが実行されていることを意味します。
22:27 $ javap -c TestMain Compiled from "TestMain.java" public class TestMain { public TestMain(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: new #2 // class java/lang/String 3: dup 4: invokespecial #3 // Method java/lang/String."<init>":()V 7: astore_1 8: new #4 // class TestMain$SubCaller 11: dup 12: invokespecial #5 // Method TestMain$SubCaller."<init>":()V 15: astore_2 16: aload_2 17: aload_1 18: invokevirtual #6 // Method TestMain$Caller.call:(Ljava/lang/String;)V 21: return }
上記の結果として、 18: invokevirtual #6 // Method TestMain$Caller.call:(Ljava/lang/String;)V これは、TestMain$SubCaller.call ではなく TestMain$Caller.call です。コンパイル時に使用されます。サブクラスの実装を呼び出すか、親クラスの実装を呼び出すかを決定します。これにより、実行時の動的バインディングのみに任せることができます。
オーバーロードとオーバーライドの場合
次の例は少し異常です。Caller クラスには call メソッドの 2 つのオーバーロードがあり、さらに複雑なのは、SubCaller が Caller を統合し、これら 2 つのメソッドを書き換えることです。実際、この状況は上記 2 つの状況が複合した状況です。
次のコードは、最初に静的にバインドされて、パラメーターが String オブジェクトである呼び出しメソッドを決定し、次に実行時に動的にバインドされて、サブクラスまたは親クラスの呼び出し実装を実行するかどうかを決定します。
public class TestMain { public static void main(String[] args) { String str = new String(); Caller callerSub = new SubCaller(); callerSub.call(str); } static class Caller { public void call(Object obj) { System.out.println("an Object instance in Caller"); } public void call(String str) { System.out.println("a String instance in in Caller"); } } static class SubCaller extends Caller { @Override public void call(Object obj) { System.out.println("an Object instance in SubCaller"); } @Override public void call(String str) { System.out.println("a String instance in in SubCaller"); } } }
実行結果は
22:30 $ java TestMain a String instance in in SubCaller
検証
上で紹介したのでここでは逆コンパイル結果のみ載せておきます
22:30 $ javap -c TestMain Compiled from "TestMain.java" public class TestMain { public TestMain(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: new #2 // class java/lang/String 3: dup 4: invokespecial #3 // Method java/lang/String."<init>":()V 7: astore_1 8: new #4 // class TestMain$SubCaller 11: dup 12: invokespecial #5 // Method TestMain$SubCaller."<init>":()V 15: astore_2 16: aload_2 17: aload_1 18: invokevirtual #6 // Method TestMain$Caller.call:(Ljava/lang/String;)V 21: return }
気になる質問
動的バインディングしないと無理なのでしょうか?
実際、理論的には、特定のメソッドのバインドは静的バインディングによっても実現できます。例:
public static void main(String[] args) { String str = new String(); final Caller callerSub = new SubCaller(); callerSub.call(str); }
たとえば、ここでは callerSub は subCaller のオブジェクトを保持しており、callerSub 変数は Final であり、call メソッドはすぐに実行されます。理論的には、コンパイラーは十分な分析によって SubCaller の call メソッドを呼び出す必要があることを知ることができます。コードの。
しかし、なぜ静的バインディングがないのでしょうか?
Caller が call メソッドを実装する特定のフレームワークの BaseCaller クラスから継承し、BaseCaller が SuperCaller から継承すると仮定します。呼び出しメソッドも SuperCaller に実装されています。
特定のフレームワーク 1.0 で BaseCaller と SuperCaller を想定します
static class SuperCaller { public void call(Object obj) { System.out.println("an Object instance in SuperCaller"); } } static class BaseCaller extends SuperCaller { public void call(Object obj) { System.out.println("an Object instance in BaseCaller"); } }
そして、そのような実装を実装するためにフレームワーク 1.0 を使用します。 Caller は BaseCaller を継承し、super.call メソッドを呼び出します。
public class TestMain { public static void main(String[] args) { Object obj = new Object(); SuperCaller callerSub = new SubCaller(); callerSub.call(obj); } static class Caller extends BaseCaller{ public void call(Object obj) { System.out.println("an Object instance in Caller"); super.call(obj); } public void call(String str) { System.out.println("a String instance in in Caller"); } } static class SubCaller extends Caller { @Override public void call(Object obj) { System.out.println("an Object instance in SubCaller"); } @Override public void call(String str) { System.out.println("a String instance in in SubCaller"); } } }
次に、静的バインディングによって上記の Caller の super.call が BaseCaller.call として実装されると判断できることを前提として、このフレームワークのバージョン 1.0 に基づいてクラス ファイルをコンパイルしました。
次に、このフレームワークのバージョン 1.1 では BaseCaller が SuperCaller の呼び出しメソッドを書き換えないと再び仮定します。次に、バージョン 1.1 では super.call が存在するため、静的にバインドできる呼び出し実装がバージョン 1.1 で問題を引き起こすという上記の仮定が適用されます。 SuperCall の呼び出しメソッド実装は、静的バインディングによって決定されると想定される BaseCaller の呼び出しメソッド実装ではありません。
そのため、実際には静的にバインドできる一部のものは、安全性と一貫性を考慮して、単純に動的にバインドされます。
最適化に関するインスピレーションはありましたか?
動的バインディングでは、実行時に実行するメソッド実装または変数のバージョンを決定する必要があるため、静的バインディングよりも時間がかかります。
そのため、全体的な設計に影響を与えることなく、メソッドや変数を private、static、final で変更することを検討できます。
Java の静的バインディングと動的バインディングの詳細については、PHP 中国語 Web サイトに注目してください。

この記事では、Javaプロジェクト管理、自動化の構築、依存関係の解像度にMavenとGradleを使用して、アプローチと最適化戦略を比較して説明します。

この記事では、MavenやGradleなどのツールを使用して、適切なバージョン化と依存関係管理を使用して、カスタムJavaライブラリ(JARファイル)の作成と使用について説明します。

この記事では、カフェインとグアバキャッシュを使用してJavaでマルチレベルキャッシュを実装してアプリケーションのパフォーマンスを向上させています。セットアップ、統合、パフォーマンスの利点をカバーし、構成と立ち退きポリシー管理Best Pra

この記事では、キャッシュや怠zyなロードなどの高度な機能を備えたオブジェクトリレーショナルマッピングにJPAを使用することについて説明します。潜在的な落とし穴を強調しながら、パフォーマンスを最適化するためのセットアップ、エンティティマッピング、およびベストプラクティスをカバーしています。[159文字]

Javaのクラスロードには、ブートストラップ、拡張機能、およびアプリケーションクラスローダーを備えた階層システムを使用して、クラスの読み込み、リンク、および初期化が含まれます。親の委任モデルは、コアクラスが最初にロードされ、カスタムクラスのLOAに影響を与えることを保証します

この記事では、分散アプリケーションを構築するためのJavaのリモートメソッドの呼び出し(RMI)について説明します。 インターフェイスの定義、実装、レジストリのセットアップ、およびクライアント側の呼び出しを詳述し、ネットワークの問題やセキュリティなどの課題に対処します。

この記事では、ネットワーク通信のためのJavaのソケットAPI、クライアントサーバーのセットアップ、データ処理、リソース管理、エラー処理、セキュリティなどの重要な考慮事項をカバーしています。 また、パフォーマンスの最適化手法も調査します

この記事では、カスタムJavaネットワーキングプロトコルの作成を詳述しています。 プロトコルの定義(データ構造、フレーミング、エラー処理、バージョン化)、実装(ソケットを使用)、データシリアル化、およびベストプラクティス(効率、セキュリティ、メンテナ


ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

VSCode Windows 64 ビットのダウンロード
Microsoft によって発売された無料で強力な IDE エディター

SublimeText3 英語版
推奨: Win バージョン、コードプロンプトをサポート!

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

mPDF
mPDF は、UTF-8 でエンコードされた HTML から PDF ファイルを生成できる PHP ライブラリです。オリジナルの作者である Ian Back は、Web サイトから「オンザフライ」で PDF ファイルを出力し、さまざまな言語を処理するために mPDF を作成しました。 HTML2FPDF などのオリジナルのスクリプトよりも遅く、Unicode フォントを使用すると生成されるファイルが大きくなりますが、CSS スタイルなどをサポートし、多くの機能強化が施されています。 RTL (アラビア語とヘブライ語) や CJK (中国語、日本語、韓国語) を含むほぼすべての言語をサポートします。ネストされたブロックレベル要素 (P、DIV など) をサポートします。

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)
