多態性 オブジェクト指向プログラミング言語では、「ポリモーフィズム」は重要な概念です。オブジェクト指向の本質はメソッドとデータの結合にあるとよく言われます。継承関係を持つクラスの場合、メソッド バインディングは最終的に子クラスが親クラス メソッドを「オーバーライド」し、親クラス参照を通じて子クラス オブジェクトを指すことで、実行時ポリモーフィズムを実現します。
説明するのは少しわかりにくいので、まずは Hello World に次いで有名な「Animal - Dog」コードを使用してポリモーフィズムを説明し、次に JVM レベルでポリモーフィズムがどのように実装されているかを分析します。
この出力は、オブジェクト指向プログラミングに慣れている Java 開発者には馴染みのあるものです。
では、仮想マシンは Animal の say を呼び出すべきか Dog の say を呼び出すべきかをどうやって知るのでしょうか? バイトコードレベルから見てみましょう。
バイトコードの 9 行目と 33 行目はそれぞれ d.say() と ad.say() に対応していますが、命令の内容は実際には同じであることに気付きましたか。それはすごいですね。 これら 2 つのメソッドが実行される前に、8 行目と 32 行目に aload 操作が行われ、これら 2 つのオブジェクトの参照がスタックの先頭にプッシュされ、後続の操作で使用できるようになります。これら 2 つのオブジェクトは、一般にメソッドのレシーバーと呼ばれます。 Golang などの言語に精通している友人にとっては、この概念は馴染み深いものです。 9 行目と 33 行目から、メソッド呼び出しのバイトコード命令とパラメーターの両方が定数プールの項目 4 を指していることがわかります。すべて同じですが、最終結果は同じではありません。ここでの焦点は、invokevirtual 命令の多態的ポインタ検索プロセス、つまり、オブジェクトの vtable に基づいて実行時にメソッドを見つけることです。 vtable とは何ですか? 前回の内容でも述べたように、命令が実行されると、スタックの上から現在のメソッドの「レシーバー」が取得され、invokerirtual を通じてこのレシーバーに対応するメソッドが実行されます。ここでの「仮想」という単語は、C++ の仮想メソッドに似ていることに注意してください。これについては話さずに、Java についてだけ話しましょう。 すべてのオブジェクトには独自の「メソッド テーブル」があり、これには独自のメソッドだけでなく、親クラスから継承されたメソッドやオーバーライドされた親クラスのメソッドも含まれます。そのため、オーバーライドとオーバーロードに対応して、メソッドテーブルにも違いが反映されます。各サブクラスが親クラスから継承すると、親クラスのメソッド テーブルのコピーが直接コピーされます。親クラスのメソッドをオーバーライドする場合、メソッド テーブル内の同じ順序のメソッドが直接更新されます。 オーバーロードは、シグネチャとパラメータの違いにより本質的に新しいメソッドとなり、メソッド テーブルに新しい要素が追加されます。 ここでのメソッド テーブルは、vtable (Virtual Method Table) と呼ばれます。表内の各メソッドは、実際の実行エントリ アドレスに対応しています。書き換えがない場合、親クラスと子クラスのアドレスは同じになり、両方とも親クラスの実装を指します。 サブクラスがメソッドをオーバーライドする場合、サブクラス メソッド テーブル内のこのメソッドのアドレスは、そのサブクラスが実装したバージョンを指します。 上記のバイトコードからわかるように、2 つのinvokevirtuals に対応する定数プールのインデックス番号は同じです。したがって、実装タイプを変更する場合は、メソッド テーブルを見つけるためにオブジェクトを変更するだけでよく、インデックスは同じままです。 観察する Java プロセスにアタッチするには、コードにラッチを追加して awiat ブロッキングを実行し、SA を起動して監視します。 クラスブラウザを選択 上記で作成したオブジェクトはクラス リストにあります。 @ 記号の後には、このオブジェクトに対応するメモリ アドレスが続きます。 Dog アドレスをコピーし、メニューから Inspector を選択します。 _vtable_len: 7 が表示されます これは、vtable の長さが 7 であり、その中に 7 つのメソッドがあることを示しています。 実際、このクラスでは親クラス Animal の say メソッドのみを書き換えます。その他は、Animal から継承された play メソッドと、スーパークラス Object の 5 つのメソッドです。次のようになります: JVM はクラスを初めてロードするときに、クラスに含まれるメソッドを解析し、メソッドが解析された後に現在のクラス vtable のサイズを計算します。 Object クラスには 5 つ以上のメソッドがあるのに、なぜ 5 つだけがカウントされるのかと疑問に思うかもしれません。では、追加する他の静的メソッドや最終メソッドについてはどうでしょうか? ここで、vtable は非静的な最終値のみを計算し、すべての計算が完了した後に vtable_len の値が取得されます。 各 Java クラスには JVM 内に独自の instanceKlass があり、vtable はこの instanceKlass の最後に割り当てられます。 64 ビット システムでは、instanceKlass 全体のサイズは 0x1b8 です。覚えておいてください。後で必要になります。上で Dog クラスのメモリ アドレスを確認しましたが、検索を続けると、他のメソッドに対応するメモリ アドレスを確認できます。 Windows -> コンソールでこれを実行します:
この値はどこから来るのでしょうか?これは、オブジェクトのメモリ アドレスと instanceKlass のサイズを加算した値から始まります。
7 つの方法があるため、7 つのアドレスを順番に検索します。 したがって、Java の対応するオーバーライドされたメソッドは、クラスがロードされたときにどの特定のメソッドに対応するかを知るためのものであり、動的バインディングまたは遅延バインディングとも呼ばれることがわかります。 要約すると、ここでの vtable は、アイアンマンのさまざまなスキルなど、すべての能力をリストするツール リストに相当します。各機能は特定の超能力を指します。私たちのコードでは、これは配列として理解でき、配列の各要素はメソッドのアドレスを指します。 興味があれば、静的メソッドを追加して、ここにあるかどうかを自分で調べることができますか?結局のところ、静的メソッドを実行するためのinvokestatic命令はないのでしょうか? この記事はWeChatの公開アカウント「Tomcat Things」から転載したものです。以下のQRコードからフォローできます。この記事を転載する場合は、Tomcat Things の公開アカウントにご連絡ください。 |
<<: 高性能 AMD クラウド ホストを選択するにはどうすればよいでしょうか? AWS、Google Cloud、UCloud、Tencent Cloud テストコンテスト
>>: マイクロサービス分散アーキテクチャでログリンクトラッキングを実装するにはどうすればよいですか?
ローカルウェブサイトの分野では、注目に値する現象がいくつかあります。ローカルウェブサイトの主な形態は...
SEO 業界に不慣れな人にとって、SEO を学ぶ方法を知ることは重要な問題です。 SEO を学ぶには...
最近、「クラウドコンピューティングサービスのセキュリティ評価に関する措置」をさらに宣伝・実施し、クラ...
Cloudsilk (旧idc.best)は、春節特別VPSプロモーションを開始しました。米国西海岸...
李娜[暁丁は、巨華軒のイベントの売上高は15万元、広告費は5万元で、最終的に商人は在庫しか稼げなかっ...
テンセントテクノロジーニュース(劉学同)北京時間9月6日のニュース、海外メディアの報道によると、テク...
最近、弊社では「SEO 会社に来れば、世の中にどんな不思議なことがあるかがわかる」という言い伝えが流...
序文この共有は、次の重要なポイントから始まります。時代: 時代の傾向と全体的な方向性を理解することに...
6月初旬、温州市で近年最大規模の違法ねずみ講事件が発生した後(詳細は本紙6月6日付A4面参照)、同市...
yoctobox.com は昨年設立された VPS 販売業者です。主に OVZ と KVM の仮想 ...
zjiは現在、香港葵湾データセンター内の香港独立サーバー(香港物理マシン)を45%割引で提供していま...
6月28日のBaiduのビッグKサイトは、SEOコミュニティに大きな波紋を巻き起こしました。Goog...
Discuz! Lab の最初の製品の 1 つである投稿内集約プラグインは、投稿内でテキストと画像を...
月々のクラウド コンピューティング費用が予想を超えないようにするには、コンテナー、容量の事前購入、そ...
ウェブサイトの最適化は、動的な環境で発展する専門職です。この専門職グループの人々の共通の特徴は、検索...