Javaのクラスローディング機構 - クラスのロード処理(解決します)

Java仮想マシンの負荷クラスの全体のプロセスは、次のとおりです。ロード、検証、準備、解像度、初期化を。接続プロセスを解決するために呼び出さ検証、準備、。今日は、解像度について話しています。

舞台を解析すると、仮想マシンさを直接参照に置き換えシンボリック参照の定数プール処理するために、シンボルの参照は、クラスファイルにCONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_infoや定数の他の種類に表示され、その段階を解析し、我々は直接参照し、シンボル参照があると述べましたどのような関連性はありますか?

  • シンボル参照:参照に記載されたシンボルの目標が設定された基準線、リテラルシンボルは、任意の形態であってもよく、限りターゲットを使用することができるように明確な目標とすることができます。シンボル参照は、目標は必ずしもメモリにロードされた基準ではないため、仮想マシンを達成するためのメモリレイアウトとは何の関係もありません。メモリレイアウトのさまざまな仮想マシンの実装は変化し得るが、それらは、シンボリック参照を受け入れることができなければならないシンボル参照のリテラル形態が明らかクラスファイル形式のJava仮想マシン仕様で定義されているので、同じです。
  • 直接参照:直接参照は、オブジェクトへの直接ポインタ、相対オフセットまたは間接的にターゲットを処理するために標的化され得ます。異なる仮想マシン・インスタンスで翻訳関連文献の仮想マシンの実装のメモリレイアウトを直接参照は、一般的にシンボルへの直接参照と同じではありませんです。あなたがその目標基準への直接参照を持っている場合は、すでにメモリ内に存在している必要があります。

(個人的な理解:分析シンボリック参照は、オブジェクトがメモリにロードされ得ることである、「直接参照は、ターゲットへの直接のポインタ、相対間接的オフセット又は位置決めすることができることである理由を直接参照になることです。?。ハンドルの定義があるので、「処理する対象は、そのオブジェクトがメモリにロードされていることを意味しますのみがステージを解析の目的が何であるかを言うためにここに現在のオブジェクトを識別し、それは時間分解の次の出現を言う必要がありますおよび解像度)が行う方法であります

仮想マシンの仕様はありません、所定解決フェーズ特定の時間に発生した、唯一の実装anewarrayを必要とし、checkcast、のgetField、getstatic、 instanceofは、invokedynamicの、invokeinterface、invokespecial、invokestatic、INVOKEVIRTUAL、LDC、ldc_w、multianewarray、新しい、putfield とputstatic 16その参照シンボルのバイトコード命令動作の前、最初のシンボルは、使用解析しますだから、仮想マシンの実装は、クラスローダを解析し、またはシンボリック参照は彼だけが必要なの前に解決するのに使用されるまで待機するシンボリック定数プール参照に上にロードされたときにそれが最終的に判断することができます。

操作に対応するコマンドは、次のとおり
anewarray、multianewarray:アレイの作成
型チェック・クラス・インスタンス:instanceofのcheckcast、
のgetField、getstatic、putfield、putstatic:アクセスクラスフィールド(静的フィールド、そうでなければクラス変数としても知られる)、インスタンスフィールドを(非静的フィールド、そうでない場合はインスタンス変数として知られている)
invokeinterface:インタフェースのメソッドを呼び出す、彼は適切なメソッド呼び出しを見つけ、このインターフェイスメソッドの実行時オブジェクトの実現を検索
invokespecialを:インスタンス初期化メソッドを含む特別な処理を必要とする方法のいくつかの例を呼び出します、プライベートメソッドとスーパーメソッド
invokestatic:クラスメソッド(静的メソッド)を呼び出す
最も一般的なJava言語の割り当てモードでオブジェクトの実際のタイプに基づいて呼び出すオブジェクトのインスタンスメソッド、派遣(派遣仮想メソッド):INVOKEVIRTUAL
invokedynamicのための:ランタイム呼び出しサイトでの動的解像度の方法は、修飾子を参照し、変更方法を実行
LDCを:定数は命令にロードされ、オペランドスタック
ldc_w:定数は、スタック命令のオペランドにロードされる
のインスタンスを作成:新しいです

(個人的な理解:人、人はこの時間を使用したシンボルであるとき、これらの16回の操作の実行は、最初に彼らが解析に使用するシンボルの、「彼らは記号を使用」などの新しいなど、そのクラスまたはインタフェースを意味します。人は解決しなければなりません)

同じ複数の解決要求へのシンボリック参照は非常に一般的なことですが、invokedynamicの命令は、仮想マシンの実装では、直接、第1の解像度の結果の記録実行時定数プール、および一定の識別で参照(キャッシュすることができます避けるように解析された状態など)の分析動作が繰り返されます。かどうかは、実際に仮想マシンがあることを確認する必要があり、分析操作を数回実行します。成功したシンボリック参照する前に解析された場合、同じエンティティに、後続の要求への参照が正常に解決されている必要があります。同様に、最初の場合第2の解像度が失敗し、その後、このシンボルの要求を解決するための他の命令は、同じ例外を受け取る必要があります。

invokedynamicのために、上記のルールは保持しません。それは以前に解決し、シンボリック参照を介しinvokedynamicの命令によってトリガに来るとき、それは、分析結果は、他のinvokedynamicの手順については、効果を取ることを意味するものではありません。invokedynamicのの目的は、本来、動的言語サポートのために指定されているので、彼は「動的呼び出しサイト修飾子」、「動的」と呼ばれ、これは実際にこの命令の時点まで待たなければならないプログラムを実行していること、対応する引用し、作業を解決することができます。対照的に、解決トリガすることができ、残りのコマンドは、ローディング・フェーズがちょうど終了したときに解決することができ、「静的」であり、まだコードを実行し始めていません。

クラスまたはインタフェース、フィールド、メソッドのクラスのための主要な分析操作、インターフェースメソッド、タイプ法、および定数の7種類、それらの定数プールタイプに対応する、シンボリック参照方法ハンドル7点クラス修飾子を呼び出します。この記事では、4の前で話します。

まず、クラスやインタフェースの解析
現在のコードがDである仮説の、我々が解析されたが、Nへのシンボリック参照を解決しませんしたい場合は、直接クラスやインタフェースのCを参照するには、その後、解析処理を完了するための仮想マシンが必要です三つのステップ:

  1. タイプは、クラスCをロードする仮想マシンが、完全修飾名は、N Dクラスローダへ送信表す配列Cではない場合 ローディングプロセスタイプにおいて、メタデータ検証ので、バイトコード検証の必要性は、このようなクラスの親クラスをロードまたは実装のような他のクラスのローディング動作をトリガすることができます。ロード処理たら例外解決プロセスが失敗してきました。
  2. Cが配列の型であり、配列要素タイプである場合、オブジェクト記述子がNであり、最初の点の規則に従って配列要素タイプをロードする同様の「Ljava /ラング/インター」形態であろう。N記述子は、先に仮定として、および要素タイプをロードする必要が「java.lang.inter」である場合には、仮想マシンと要素代表のこのアレイの寸法によってオブジェクトの配列を生成します。
  3. 上記の手順は、いずれかの例外は表示されない場合は、Cは、実際に仮想マシンで有効なクラスやインタフェースとなっているが、彼らは分析前の完成にCへのアクセス権を持っているかどうかもシンボリック参照の検証のために、Dを確認します。あなたがアクセス権を持っていないことを発見した場合は、「lava.lang.IlldgalAccessError」異常スローされます

次のように個人的な理解がある:
私たちはメインでpersonaaを定義すると、メインクラスローダは、Personクラスをロードするために行くだろう、それはまた、親クラスの人(もしあれば)にロードすることができます。エラーまたは例外がない場合、人は有効なクラスを持つことになり、仮想マシン内で実際にですが、シンボリック参照を検証するためにも、彼らは分析が完了する前にD Cへのアクセス権を持っているかどうかを確認します。プールの量は、このシンボルを記録するために直接参照して実行されるため、複数の新しい人ならば、頻繁に繰り返されていない解決、および定数が解決状態として同定しました。

public class Person {
	public String clientName;
	public String clientId;

	public String getClientName() {
		return clientName;
	}

	public void setClientName(String clientName) {
		this.clientName = clientName;
	}

	public String getClientId() {
		return clientId;
	}

	public void setClientId(String clientId) {
		this.clientId = clientId;
	}
}

public class Main {
	public static void main(String args[]){
		Person personaa = new Person();
	}
}

第二に、フィールドが解析され
、フィールド内のすべての最初に解析するために、インデックスCONSTANT_Class_infoシンボリック参照のテーブルclass_indexエントリになり、シンボリック参照の分野にわたり未解決解決するために、それはフィールドのシンボルがクラスまたはインタフェースの参照に属しています。クラスまたはインタフェースのシンボルは、引用の解析の過程で何らかの異常がある場合は、フィールドにはシンボリック参照を解決するために失敗になります。解像度が正常に完了されている場合は、このフィールドのクラスまたはインタフェースに属します手順に従って、後続の検索フィールドのためのC、C仮想マシン仕様の要件によって表されます。

  1. C自体が目標と一致しているフィールド名とフィールド記述子シンプルが含まれている場合、このフィールドは終わりを見つけるために、直接参照を返されます。
  2. インターフェースは、フィールド名とフィールド記述子がシンプルであり、目的は戻り値と一致して含まれている場合はそれ以外の場合は、Cインタフェースで実装されている場合は、再帰的に各インターフェイスと父親からインターフェイスを検索継承をフォローアップしますこのフィールドへの直接参照、終了を見つけます。
  3. Cはjava.lang.Objectのない場合は、親クラスはフィールド名とフィールド記述子の単純なターゲットに一致している含まれている場合はそうでない場合、それは、親クラス再帰検索からの継承をフォローアップし、その後、これに戻ります直接参照フィールドと終了を探して。
  4. それ以外の場合は、ルックアップが失敗し、例外がjava.lang.NoSuchFieldErrorのスローされます。

検索は、プロセスへの参照が成功し返した場合、それは、アクセス許可を確認するために、フィールドになり、フィールドへのアクセス権を持っていないことが判明すれば、java.lang.IllegalAccessErrorは例外をスローします。
実際には、仮想マシンのコンパイラの実装が規制要件の数よりも厳しいこともあり、同じ名前のフィールドがある場合も、Cインタフェースと親クラス、または複数のインタフェースを同時に自分の中や親クラスに表示されますこれは、コンパイラがコンパイルを拒否する可能性が表示されます。注釈サブクラス「= 4のpublic static int型のA」と、次のコードで 、 親フィールドAが存在し、インターフェース、コンパイラは、「フィールドSub.Aが曖昧である」プロンプトが表示されます、方法の曖昧ですコンパイラは、コードで使用される方法を決定し、コンパイルすることを拒否することができません。

public class FieldResolution {
	
	interface Interface0{
		int A = 0;
	}
	
	interface Interface1 extends Interface0{
		int A = 1;
	}
	
	interface Interface2{
		int A = 2;
	}
	
	static class Parent implements Interface1{
		public static int A = 3;
	}
	
	static class Sub extends Parent implements Interface2{
		public static int A = 4;
	}
	
	public static void main(String[] arg){
		System.out.println(Sub.A);
	}
}

個人的な理解は:
フィールドには、このフィールドのクラスが配置されている解決するために、すべての最初に解決しました。例えば、上記のコードは、サブクラスは、仮想マシン(サブ解析クラスの実際のクラス、言って最初の点)への直接参照を持つことを保証するために、Sub.Aを呼び出すときサブクラスを解決する必要があります。問題がなければ、あなたはすでにメモリ内のこのクラスは、(Cとする)ことを考えることができます。そして、そのようなフィールドが存在しないかどうかを確認するために見て内部クラスCでの仮想マシンは、(単純名フィールド記述子を見つけるとフォロー)。任意の直接返した場合。インターフェースはCで実装されている場合は、内部のすべての親インターフェイスを見つける必要があります。Cは、親クラスを持っていますが、また親クラス内で検索した場合。私は例外をスローするように言葉を見つけることができませんでした。我々は成功した場合、権限も確認する必要があります。
サブ場合クラスの上記のコード「パブリックstatic int型A = 4」コメント、あなたがメインのSystem.out.println(Parent.A)で書かれたコードを実行することができ、またはするSystem.out.printlnを(Interface1.A );またはのSystem.out.println(Interface2.A);このフィールドの構文解析、及びインタフェースの親クラスの実装時にも解決されることを実証しています。

第三に、クラスメソッドが解決する
も正常に解決場合の参照方法、我々はまだCを使用属する予防class_index記号キーインデックステーブルのクラスまたはインタフェースの型を解析する必要があるとして、最初のステップクラスの分析方法および分析フィールドをこのクラスは、次以降の仮想マシンが、クラスメソッドは、次の手順を検索します表しています。

  1. class_indexインターフェイス、それが直接java.lang.IncompatibleClassChangeError例外スローされるクラスメソッドテーブルインデックスCに見つかった場合定数型定義されたクラスのメソッドとインターフェースメソッドの参照記号は、分離されています。
  2. 最初のステップによって場合、探索を終了するために、この方法は、参照を返す場合、単純な名前とクラスCと一致するターゲットの記述が存在するかどうかを調べるために、
  3. そうでない場合は、インターフェースおよびその親インターフェイス再帰的メソッドのクラスCの実装のリストに簡単な名前と一致するようにターゲットの記述があるかどうかを調べるために、それは、このメソッドへの参照を返す場合、終了を見つけます。
  4. それ以外の場合は、インタフェースクラスCのリストと一致するように、単純名とターゲットの記述があるかどうかを調べるために、親インターフェイス再帰的な方法を達成するため、マッチング方法は、そのCは、検索が終了し、抽象クラスであることを証明するために存在している場合、例外がスローされjava.lang.AbstractMethodError
  5. それ以外の場合は、メソッド・ルックアップを宣言することはjava.lang.NoSuchMethodErrorのをスローし、失敗しました。

プロセスが正常に直接参照を見つけることが返された場合、このメソッドへのアクセス権を持っていないことが判明した場合最後に、この方法は、ないIllegalAccessErrorをするjava.langスローされます、アクセス許可を確認します。

個人的な理解:クラス分析方法および分析の分野、等、(Cこのクラスによって表される)第一のクラスの分析方法。Cは唯一のクラスではなく、インタフェース、もしそうであれば、エラーとすることができます。他の分析フィールドのように。

第四に、インタフェース方法解決
インターフェース方法は、これはまだ次のようになり、仮想マシン続いCで記述されたインターフェースを表し、正常に解決場合クラスまたはインタフェースのシンボル方法class_index入力インターフェース方法テーブルのインデックスは、参照を属して解析する必要がありますインターフェースメソッドは、後続検索ステップ。

  1. クラスメソッドは、異なる解決するために、それがCクラスではなくインタフェースであるインデックス内のインターフェースメソッドテーブルclass_indexエントリに見つかった場合、それはjava.lang.IncompatibleClassChangeError直接スローです。
  2. このメソッドの戻り値を直接参照があればそうでない場合は、簡単なメソッド名と一致するように、ターゲットの記述がありますCのインターフェイスを探し、終了を見つけます。
  3. 再帰検索ではそれ以外の場合は、親インタフェースインタフェースCと一致するように、ターゲットの単純名と記述方法があるならば、それは、これを返す場合java.lang.Objectクラスは、(ルックは、Objectクラスが含まれます)、表示されるまで直接参照メソッド、端を見つけます。
  4. それ以外の場合は、メソッド・ルックアップを宣言することはjava.lang.NoSuchMethodErrorのをスローし、失敗しました。

アクセスの問題が存在しないので、インタフェースのすべてのメソッドは、デフォルトで公開されているので、インターフェイスメソッドのシンボルは、ないIllegalAccessErrorをするjava.langを投げる解決しません。

個人的な理解:Cが唯一のインターフェースである、異なるクラス、クラスメソッドとインターフェイスメソッドで呼び出すことはできません。

おすすめ

転載: blog.csdn.net/huqianlei/article/details/90740165
おすすめ