HotSpot 仮想マシンのソースコードから Java のアクセス制御修飾子を理解する

HotSpot 仮想マシンのソースコードから Java のアクセス制御修飾子を理解する

[[340301]]

前回の Ribbon ソース コード分析の記事で、読者から次のような質問がありました。「XX クラスはパッケージ プライベートですが、書き直してもエラーは発生しないでしょうか?」答えは、実際には XX クラスはパッケージプライベートではなく、保護された静的内部クラスであるため、書き換えてもエラーは発生しないということです。

Java アクセス制御修飾子の役割に関しては、私も最初に Java を学んだときは暗記に頼っていました。さらにコードを書いていくうちに自然と理解できましたが、基礎となる実装について非常に興味があったので、長年の疑問に答えるために、HotSpot 仮想マシンのソース コードから答えを見つけようともしました。

クラス、フィールド、メソッドのアクセス制御修飾子は何ですか?

プライベート <private>、サブクラスにアクセス可能 <protected>、パブリック、パッケージ プライベート <package>、アクセス制御修飾子のないデフォルトではパッケージ プライベートです。

アクセス範囲 プライベート パッケージ 保護された 公共
同じクラス アクセス可能 アクセス可能 アクセス可能 アクセス可能
同じパッケージ内の他のクラス アクセスできません アクセス可能 アクセス可能 アクセス可能
異なるパッケージ内のサブクラス アクセスできません アクセスできません アクセス可能 アクセス可能
異なるパッケージ内の非サブクラス アクセスできません アクセスできません アクセスできません アクセス可能

パッケージ private <package> は、同じパッケージ内のクラスだけがアクセスでき、他のパッケージ内のクラスはアクセスできないことを意味します。

今日は、Java 仮想マシンを詳しく調べて、これらのアクセス制御修飾子のセマンティクスの実装について検討します。

InstanceKlass は、HotSpot VM のクラス ファイル構造に対応するデータ構造です。 InstanceKlass オブジェクトは、Java クラスが HotSpot VM によってロードされ、メソッド領域に格納された後に生成される C++ オブジェクトです。 Java コードで使用する Class オブジェクトは、実際には InstanceKlass のミラーです。

Java は、「this.」、「support.」、「a particular object.」の使用をサポートします。メソッド、または「特定のクラス」を呼び出します。静的メソッドを呼び出します。私たちの観点からすると、これはクラスの静的メソッドまたはオブジェクトのメソッドを呼び出していますが、仮想マシンでは違いはなく、すべてメソッド呼び出しです。

静的メソッドとオブジェクト メソッドの呼び出しの唯一の違いは、オブジェクト メソッドを呼び出すには、メソッド パラメーターで "this" 参照を渡す必要があることです。これは、コンパイラが Java コードをバイトコードにコンパイルするときに自動的に追加される暗黙的なパラメーターです。

「this」の使用の違い。そして「サポート」。 Java コードで独自のメソッドと親クラスのメソッドを呼び出す場合の違いは、生成されたメソッド呼び出しバイトコード命令のオペランドが異なる Methodref 定数を指し、メソッドの最初の暗黙的なパラメータによって渡されるオブジェクトが同じであることです。 Methodref 定数は、クラス名、メソッド名、メソッド記述子を含むメソッドへのシンボリック参照を参照します。

クラスのロードプロセスには、ロード、リンク、初期化の 3 つの段階が含まれることがわかっています。リンク段階は、検証、準備、解析の 3 つの段階にさらに分けられます。次の図はクラスのロード段階を理解するのに役立ちますが、正確ではありません。

Java 仮想マシン仕様では、クラスをロードするときに実行する必要があることのみが指定されており、順序に関する厳密な要件はありません。

次の図は、HotSpot 仮想マシン クラスのロード ソース コードを読んで、著者がまとめたフローチャートであり、参考用です。 (元の画像が必要な場合は、公式アカウント「hotspot」に返信してください)

HotSpot 仮想マシンでは、ロード フェーズの後にリンク フェーズの準備フェーズが完了します。リンクフェーズの検証も複数の検証に分割されます。このうち、ファイル形式の検証とメタデータの検証はロードフェーズで相互に完了しますが、バイトコード検証フェーズはクラスの初期化前にトリガーされ、解析フェーズはクラスのロードが完了した後に実行されます。

new、getstatic、putstatic、invokestatic など、クラスの初期化を引き起こすいくつかの命令では、仮想マシンがこれらの命令を実行するときに、まずクラスが初期化されているかどうかを判断します。そうでない場合は、クラスの初期化を完了します。リンク フェーズは、クラス初期化フェーズの前にトリガーされます。

リンク フェーズの解析段階は、Java 仮想マシンが定数プール内のシンボリック参照を直接参照に置き換えるプロセスです。 Java 仮想マシン仕様によれば、定数プール内のシンボリック参照定数 (CONSTANT_Class_info、CONSTANT_Field_info、CONSTANT_Methodref_info など) を指すオペランドを必要とする ane-warray、checkcast、getfield、getstatic、instanceof、invokedynamic、invokeinterface、invoke-special、invokestatic、invokevirtual、ldc、mulianewarray、new、putfield、putstatic などの命令を実行する前に、使用されるシンボリック参照をまず解析する必要があります。

シンボリック参照は、参照先クラスの CONSTANT_Class_info、クラスの参照先フィールドの CONSTANT_Field_info、クラスの参照先メソッドの CONSTANT_Methodref_info など、一連のシンボルを使用して参照先を記述します。

シンボル参照の検証は解析フェーズ中に行われます。シンボル参照の検証には、文字列で記述された完全修飾名が対応するクラスを見つけることができるかどうか、単純名で記述されたメソッドとフィールドが指定されたクラスに存在するかどうか、およびシンボル参照内のクラス、フィールド、およびメソッドのアクセス可能性が含まれます。 、公共、 )。

HotSpot 仮想マシンの実装では、解釈実行と動的呼び出し (invokedynamic) の場合、シンボリック参照が使用される前に解決フェーズが実行されます。

メソッド呼び出しソースコード: javaCalls.cpp;リンク解決ソースコード: linkResolver.cpp;

  1. // クラスをチェックする
  2. リンクリゾルバ::check_klass_accessability
  3. // チェック方法
  4. リンクリゾルバ::check_method_accessability
  5. // フィールドをチェックする
  6. LinkResolver::check_field_accessability

これらのメソッド呼び出しは、最終的に Reflection::verify_field_access メソッドなどの Reflection クラスの対応する verify メソッドを呼び出して、アクセス可能かどうかの判断を完了します。

Java 仮想マシンは、クラス ファイル構造を解析するときとバイトコード検証フェーズ中に、アクセス制御修飾子も検証します。

たとえば、クラス ファイル構造を解析するときに、親クラスを継承できるかどうかを確認します (Reflection::verify_class_access)。

クラスのアクセス修飾子は、クラスが他のクラスからアクセスできるかどうかを決定します。クラス ファイル構造の解析段階では、仮想マシンは、現在のクラスが親クラスを継承できるかどうか (親クラスのアクセス制御修飾子によって決定)、および各インターフェイスを実装できるかどうか (インターフェイスのアクセス修飾子によって決定) を確認できます。

バイトコード検証フェーズでは、現在のクラスがターゲット クラスの保護されたメソッドまたはフィールドにアクセスできるかどうかが検証されます。

バイトコード検証フェーズでは、仮想マシンはクラスの各メソッド内の各バイトコード命令を検証しますが、バイトコード検証フェーズでは、仮想マシンは getfield 命令に対してのみ check_protected 検証を実行します。バイトコード検証フェーズではアクセス制御の検証はあまり行われていないことがわかります。

この記事はWeChatの公開アカウント「Java Art」から転載したものです。下のQRコードからフォローできます。この記事を転載する場合はJava Art公式アカウントまでご連絡ください。

[[340304]]

<<:  誰かがテンセントミーティングの計算をしたところ、5か月で714億元の社会コストが節約されたことが判明した。

>>:  JavaアプリケーションのKubernetesへの移行が加速している

推薦する

オーディオとビデオについての理解を深めましょう。ファーウェイクラウドRTCは最先端の技術を統合

[51CTO.comからのオリジナル記事] 2020年の世界的なCOVID-19パンデミックにより、...

16 年間の革新と反復を経て、クラウド コンピューティングは今後どこへ向かうのでしょうか?

私たちは前例のない技術革新の時代に生きています。最も速い反復、最も幅広い応用、そして最も広範囲にわた...

2011 年のトップ 10 SEO イベントのレビュー

2011年も終わりに近づき、多くのウェブサイトは年末の総括や年末レビューの作成に忙しい時期です。SE...

スマート ビジネス: 分散クラウド テクノロジーの秘密を探り、企業のビジネス価値を創造し、コストを削減し、生産性を向上させましょう。

クラウド コンピューティングがなければビジネスはどうなるか想像できますか?この質問に対する答えとして...

B側チャネル操作のクローズドループ分析

インダストリアルインターネットはBエンド市場への進出に力を入れています。Bエンドチャネル運営において...

ウェブサイトの運営にはオフラインとオンラインを組み合わせる必要がある

インターネットでお金を稼ぎたい個人ウェブマスターとして、私が毎日最も考えているのは、自分のウェブサイ...

米国ロサンゼルスのprofitserverの無制限トラフィックVPSの簡単なレビュー

Profitserverは2003年にロシアのチェリャビンスクで設立されたサービスプロバイダーです。...

Struts2 の脆弱性分析: ハッカーの攻撃と防御による公式トラブル

著者:顧暁波Appleの開発者向けウェブサイトがダウンしたことで、1週間前から公開されていたApac...

マルチクラウドの世界におけるクラウドコンプライアンス戦略

複数のクラウド コンピューティング プロバイダーのクラウド コンピューティング サービスを使用する場...

アルゴリズムは電子商取引をサポートできない

興味関心に基づく電子商取引の概念が提案されてからしばらく経ちますが、Douyin は単純な短編ビデオ...

中国インターネット広告レポート

今後数年間は、トラフィック モデルのエコ化 (複数の場所、複数の形式) とシナリオベースのトラフィッ...

優れたウェブマスターツールの推奨事項: Baidu 外部リンクツール

ウェブサイト上の外部リンクの数は、常に重要な SEO 最適化指標となっています。以前は、ウェブサイト...

2020年テンセントグローバルデジタルエコシステムカンファレンスが9月に開催予定:クラウドへの移行は初めて、デジタル経済の新たなトレンドを解釈

8月20日、テンセントから、2020年テンセントグローバルデジタルエコシステムカンファレンスが9月9...

Namecheap-Register.com 4月下旬に0.98ドルで販売開始

今回、ドメイン名を 0.98 ドルで登録できるのは新規ユーザーのみです。Namecheap にすでに...

SEO最適化に関する簡単な説明:キーワード、ウェブサイトの最適化、外部リンクの構築

インターネット時代の到来により、独自の Web サイトを構築する人が増えています。しかし、毎日のトラ...