17

Java クラスローダとは何か、独自のクラスローダを作成する/*なぜ*方法については、 1,000 万の記事やドキュメントがありますが、それらはすべて、私が簡単な答えを見つけることができないいくつかのことを想定しているようです!

クラスローダの仕事、つまりバイトコードを読み取り、そこからオブジェクトを構築することを理解しています。異なるクラスローダーはこれを異なる方法で行います。

しかし、自分のコードでクラスローダー API に対してコーディングする必要はなく、独自の API を記述する必要もなかったので、のコードが実際にいつ起動するかを理解するのは非常に困難です。ClassLoader

例えば:

public static void main(String[] args) {
    Fizz fizz = new Fizz();
    fuzz.buzz();
}

ここにFizzオブジェクトがあります。をインスタンス化する前にFizz、クラスローダーを起動しFizz.classてそのキャッシュにロードする必要があります。これはいつ、どこで起こっているのですか?!?! 私のコードでは明示的ではないので、暗黙的に JRE のどこかにあるはずです...?

その質問に接して、たとえば、独自のクラスローダーを作成しWidgetClassLoader、アプリケーションのすべてのクラスをロードするように構成したい場合、またはおそらく私のFizz.class. WidgetClassLoader? 私のコードはこのクラスローダを明示的に呼び出す必要がありますか、それとも最初の例のように暗黙的でしょうか? 前もって感謝します!

4

4 に答える 4

7

あなたの質問は、今考えているほど些細なことではありません。

Fizz の例: Fizz はいつロードされますか? これはJLS (Chapter 5.4: Linking)で定義されています。Fizz がいつロードされるかは定義しませんが、目に見える動作については保証します。when の部分については、Fizz が見つからない場合、Fizz にアクセスする最初のステートメント (Fizz fizz = new Fizz()) から例外がスローされます。特にこの場合、式の右側が最初に評価されるため、新しい Fizz() になると確信しています。次のように書いた場合:

Fizz fizz = null;
fizz = new Fizz();

この場合、Fizz クラスへの最初のアクセスであるため、Fizz fizz = null は既に例外をスローします。

誰が Fizz をロードしますか? クラスをロードする必要がある場合、そのクラスを必要とするコードに「属する」クラスローダーを使用してクラスを取得します。Fizz の例では、これは main メソッドでクラスをロードしたクラスローダーになります。もちろん、Fizz を自分でロードできない場合、クラスローダはその親クラスローダに委譲することを選択できます。

JVM でClassLoaderを使用するはどうすればよいですか? 明示的または暗黙的の 2 つの方法があります。明示的に: メソッドを呼び出すことにより、独自のクラスローダーを介してクラスをロードできます。暗黙的: クラスローダからすでにロードされているクラスからコード (メソッドまたはイニシャライザを意味する) を実行し、そのプロセスでクラス参照を解決する必要がある場合、コードをロードしたのはクラスローダであるため、クラスローダが自動的に使用されます。最初の場所。

于 2012-07-18T16:06:39.587 に答える
3

Java にはデフォルトのクラスローダーがあります。これは、デフォルトのクラス パスでクラス宣言を探します。独自のクラス ローダーを作成する場合は、親クラス ローダーを設定できます (設定する必要があります)。他に何もない場合は、これがデフォルトになります。そうしないと、クラス・ローダーは Java API クラスを見つけることができません。Java がクラスを探す場合、カスタム クラス ローダーではなく、親クラス ローダーから探し始めます。これに親がある場合、そこから始まります。クラスが見つからなかった場合にのみ、次の子クラス ローダーを使用して再試行します。これも子供がいる限り続きます。チェーン内のどのローダーでもクラスが見つからない場合は、 aClassNotFoundExceptionがスローされます。

もちろん、Java は、( を呼び出して) 最初にデフォルトのクラス ローダーとして設定するか、Thread.currentThread().setContextClassLoader()( を呼び出して) 手動でクラスをロードした場合にのみ、クラス ローダーを使用しますloadClass()

クラスローダーが呼び出されるタイミングがわかりません。importプログラムの開始時( として宣言されたすべてのクラス)またはクラスの最初の使用時(変数宣言またはコンストラクター呼び出し)に呼び出されると思います。

于 2012-07-18T15:46:56.330 に答える
0

クラスローダと、それらがいつ、どのように機能するかに興味がある場合は、OSGi 仕様も参照してください。非常に興味深い読み物になると思います。OSGi は Java のフレームワークであり、モジュール性、明確なコード分離、およびライフサイクル管理を提供し、現時点で非常に人気があります (たとえば、Eclipse 自体は 1 つに基づいています)。

OSGi はクラスローダを多用しており、仕様内でクラスローディングに関するすべてがいつ、どのように行われるかについての非常に優れた説明があります。基本的に、バンドルごとに個別のバンドル クラスローダーがあり (これがモジュールの呼び出し方法です)、これらのクラスローダーは依存関係を処理し、他のバンドルから正しいクラスを取得します。

于 2012-07-19T10:29:12.497 に答える
0

クラスの実際の作成は で行われdefineClassます。クラスは、いくつかのソースのいずれかからのバイト配列を使用して作成されます。

に到達するための通常のパスdefineClass(これは ですprotected) は経由ですfindClass(もちろん、これも ですprotected)。したがって、通常のエントリ ポイントはloadClass-> findClass->defineClassです。しかし、特別な場合には他の方法があります。

(全体は非常に複雑であり、保護がより複雑になり、アクセスのモードがより多様になるにつれ、層を追加してきた歴史を表しています。)

于 2012-07-18T16:17:04.787 に答える