クラスローダチュートリアル
1.はじめに
クラスローダ中心的な役割は、それらの記憶を実行するJVMの後にコンパイル済みのクラスファイルをロードすることです。JVM仕様の中で、クラスローダは三種類に分け:
ブートストラップクラスローダ(BootClassLoader)
拡張クラスローダ(ExtClassLoader)
システムクラスローダ(AppClassLoader)
2.分類ローダー
2.1ブートストラップクラスローダ
ブートストラップクラスローダは、メインクラスは、JDKライブラリ(libディレクトリにJAVA_HOME \ jarファイル)自体が、これらのライブラリは、JDKコア・クラス・ライブラリ(rt.jarの)あり、そして最も重要なロードロードするようにこれは、ロードと初期化を完了することです。そして、ローダは、C言語を使用しています。
2.2拡張クラスローダ
拡張クラスローダはJDKの拡張パッケージをロードするために、メインリースjarファイル(JAVA_HOME \ libに\ extにヘッドjarファイル)で、これらのファイルは、JDKのクラスライブラリを拡張しています。
2.3システムクラスローダ
中心的な役割ローダがクラスパスとjarファイルにクラスファイルをロードしているシステムでは、これらのライブラリは、通常、開発者自身によって書かれているので、これらのクラスは、システムクラスローダによってロードが完了しています。
3.委任モデル
実装クラスのロードでは、最初のシステムクラスローダで始めたが、それはクラスローダを拡張する権利の実現にロードされ、同様に、拡張クラスローダは、ブートクラスローダに実行をロードしますあなたはブートストラップ・クラス・カテゴリーによってロードされていないライブラリをロードする必要がある場合は、最終的に、ブートストラップクラスローダによってロードされ始めると、それは、拡張クラスローダーをロードする権利を返します。ライブラリがロードされたカテゴリの拡張クラスローダではなく、最終的に完了するために、システムクラスローダに引き渡された場合にも、このプロセスが委託されています。以下のようなシステムライブラリ、ロード時に安全性を確保するためにそうする部屋の目的:これらのクラスであればあるため、ブートストラップクラスローダによって完成されなければならないなど、オブジェクト、Stringクラスには、、、他のクラスローダに引き渡されるべきではありませんライブラリのロードをユーザが操作することができた後、それは危険なクラスにつながることができます。例:ユーザーがクラスのメソッドをオーバーライドしたり、変更することができ、それが絶対的に禁止されています。
委任モデル:
共通API 4.クラスローダ
C言語で実装されているブートクラスローダーに加えて、他のクラスローダのClassLoaderは、このクラスは、対応するAPIのローディングを提供するだけでなく、解析プロセスのファーストクラスのロードおよび初期化を完了するために、このクラスから継承します。
API | 説明 |
---|---|
getParent() | 上のクラスローダを取得 |
loadClass(文字列名) | ロードされたクラスの名前のために名前を付け、findClassメソッドを呼び出しての間接的な方法になります。このプロセスでは、クラスの例を返します。 |
findClass(文字列名) | クラスの名前の名前が、それは、クラスのインスタンスを返し、ロードされます。通常、カスタムクラスローダは、このメソッドをオーバーライドします。 |
findLoadedClass(文字列名) | クラス名の名前を確認し、既にクラスがnullの場合、それは、クラスのインスタンスを返し、前にロードされ、それがロードされ、またはすでにロードされないことを意味します |
defineClass(文字列名、バイト[] B、オフint型、int型のlen) | Bは、Javaのクラスのオブジェクトにバイナリデータのバイト配列に変換します |
resolveClass(クラスC) | 分析し、指定されたクラスへの接続 |
2.カスタムクラスローダ
我々はまた、カスタムクラスローダ、あなただけにfindClassは通常、親クラスのメソッドをオーバーライドする必要があり、ClassLoaderを継承する必要がありますすることができます。クラスローダのカスタムクラスローダそれがAppClassLoaderであることに留意すべきであるデリゲートのパターンに従います。
クラスローダ{公共延びDemoClassLoaderクラス / ** *クラスローダルートパス * / プライベート文字列loadRootPathと、 公衆DemoClassLoader(文字列loadRootPath){ this.loadRootPath = loadRootPath; } / ** *オーバーライドにfindClass親クラス * @param名完全なクラス名をロードする * @return *は、ClassNotFoundExceptionが@throws * / @Override 保護されたクラスは、<?>にfindClass(文字列名){ClassNotFoundExceptionがスロー I / O操作が流れ読み取りおよび書き込み用クラスファイルの絶対パスを構築// 文字列のロードパスをconvertNameToPath loadRootPath + =(名); //入力することにより、メモリにクラスファイルの中でストリーム ファイルファイル=新しいファイル(ロードパスを) 。 バイト[]バイト= readClassFile(ファイル); 直接クラスに//アレイは、オブジェクト <?>;クラス= clazz defineClass(名前、バイト、0、bytes.length) 戻りclazz; } / ** *ファイルオブジェクトをクラスファイルがメモリに読み込まれたバイト配列を返します * @paramファイル * @return * / プライベートバイト[] readClassFile(ファイルfile){ //構築する入力ストリームをファイル 試して(= FileInputStreamの新しい新しいFISのFileInputStream(ファイル); ByteArrayOutputStream BAOS =新しい新しい()){ByteArrayOutputStream INT LEN = 0; バイト[]バイト=新しい新しいバイト[1024]; !一方((LEN = fis.read(バイト0、bytes.length))= -1){ //読み取り撮影した直接キャッシュに保存されています baos.write(バイト0、LEN); } //直接流れは直接の配列を返し 、戻りbaos.toByteArray() }キャッチ(IOExceptionをE){ e.printStackTrace()と、 新たな新規のRuntimeException(E)を投げます; } } / ** *相対パスの完全なクラス名を変換する * @return * / プライベートconvertNameToPathストリング(文字列名){ ;文字列のパス= name.replace( " " File.separator)+"の.class" リターンパス。 } }
パブリッククラスこんにちは{ 公共の静的な無効メイン(文字列[]アルゴ){ System.out.print(「こんにちは、世界」); } }
{メインクラス公開 パブリック静的な無効メイン(文字列[]引数)は例外{スロー //テストカスタムクラスローダ 新しい新しいDemoClassLoader DC =(「F:/ S3 /クラスローダ」+ File.separator)DemoClassLoaderと、 クラスclazz = DC。 loadClass( "こんにちは"); オブジェクトclazz.newInstanceこんにちは=(); hello2のclazz.newInstanceのオブジェクト=(); インスタンス化//後のオブジェクトのターゲット出力 するSystem.out.println(こんにちは); System.out.printlnは(hello2の); //出力ロードするクラスローダ のSystem.out.printlnを(clazz.getClassLoader()); } }
出力:
// Classオブジェクトは、の出力を表し 677327b6 @こんにちは ローダーで//をクラスファイルをロードし、クラスオブジェクト生成器は、同じである 677327b6 @こんにちは //このクラスはDemoClassLoader、すなわちカスタムローダーcom.companyでロードされます。 DemoClassLoader @ 74a14482
注:同じクラスファイルをロードするために別のクラスローダである場合、作成されたClassオブジェクトが同じではありません。