この素敵なチュートリアルからSunのからの:
動機
CやC ++などの静的にコンパイルされたプログラミング言語で記述されたアプリケーションは、ネイティブのマシン固有の命令にコンパイルされ、実行可能ファイルとして保存されます。コードを実行可能なネイティブコードに結合するプロセスは、リンクと呼ばれます。個別にコンパイルされたコードを共有ライブラリコードとマージして、実行可能なアプリケーションを作成します。これは、Javaなどの動的にコンパイルされるプログラミング言語では異なります。Javaでは、Javaコンパイラによって生成された.classファイルは、Java仮想マシン(JVM)にロードされるまでそのままです。つまり、リンクプロセスは、実行時にJVMによって実行されます。クラスは「必要に応じて」JVMにロードされます。また、ロードされたクラスが別のクラスに依存している場合、そのクラスもロードされます。
Javaアプリケーションが起動されると、最初に実行されるクラス(またはアプリケーションへのエントリポイント)は、main()と呼ばれるpublic static voidメソッドを持つクラスです。このクラスは通常、他のクラスへの参照を持ち、参照されたクラスをロードするすべての試みはクラスローダーによって実行されます。
この再帰的なクラスローディングと一般的なクラスローディングのアイデアを理解するには、次の単純なクラスを考えてください:
public class HelloApp {
public static void main(String argv[]) {
System.out.println("Aloha! Hello and Bye");
}
}
-verbose:classコマンドラインオプションを指定してこのクラスを実行し、ロードされているクラスを出力すると、次のような出力が得られます。リストが長すぎてここに表示できないため、これは部分的な出力であることに注意してください。
prmpt>java -verbose:class HelloApp
[Opened C:\Program Files\Java\jre1.5.0\lib\rt.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\jsse.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\jce.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\charsets.jar]
[Loaded java.lang.Object from shared objects file]
[Loaded java.io.Serializable from shared objects file]
[Loaded java.lang.Comparable from shared objects file]
[Loaded java.lang.CharSequence from shared objects file]
[Loaded java.lang.String from shared objects file]
[Loaded java.lang.reflect.GenericDeclaration from shared objects file]
[Loaded java.lang.reflect.Type from shared objects file]
[Loaded java.lang.reflect.AnnotatedElement from shared objects file]
[Loaded java.lang.Class from shared objects file]
[Loaded java.lang.Cloneable from shared objects file]
[Loaded java.lang.ClassLoader from shared objects file]
[Loaded java.lang.System from shared objects file]
[Loaded java.lang.Throwable from shared objects file]
.
.
.
[Loaded java.security.BasicPermissionCollection from shared objects file]
[Loaded java.security.Principal from shared objects file]
[Loaded java.security.cert.Certificate from shared objects file]
[Loaded HelloApp from file:/C:/classes/]
Aloha! Hello and Bye
[Loaded java.lang.Shutdown from shared objects file]
[Loaded java.lang.Shutdown$Lock from shared objects file]
ご覧のとおり、アプリケーションクラス(HelloApp)が必要とするJavaランタイムクラスが最初にロードされます。
Java 2プラットフォームのクラスローダー
Javaプログラミング言語は進化し続けており、アプリケーション開発者の日常生活をより簡単にします。これは、基本的なメカニズムの実装の詳細ではなく、ビジネスロジックに集中できるようにすることで、人生を簡素化するAPIを提供することによって行われます。これは、Javaプラットフォームの成熟度を反映するためのJ2SE 1.5からJ2SE 5.0への最近の変更から明らかです。
JDK 1.2以降、JVMに組み込まれているブートストラップクラスローダーが、Javaランタイムのクラスのロードを担当しています。このクラスローダーは、ブートクラスパスにあるクラスのみをロードします。これらは信頼できるクラスであるため、信頼できないクラスの場合と同様に検証プロセスは実行されません。ブートストラップクラスローダーに加えて、JVMには、標準の拡張APIからクラスをロードする拡張クラスローダーと、一般的なクラスパスおよびアプリケーションクラスからクラスをロードするシステムクラスローダーがあります。
複数のクラスローダーがあるため、それらはルートがブートストラップクラスローダーであるツリーで表されます。各クラスローダーには、その親クラスローダーへの参照があります。クラスローダーは、クラスをロードするように要求されると、アイテム自体をロードする前に、その親クラスローダーに問い合わせます。次に、親はその親に相談します。したがって、現在のクラスローダーが関与するのは、すべての祖先クラスローダーがクラスを見つけられない場合だけです。つまり、委任モデルが使用されます。
java.lang.ClassLoaderクラス
java.lang.ClassLoader
JVMが動的にロードクラスでの方法を拡張する必要があるアプリケーションによってサブクラス化することができる抽象クラスです。java.lang.ClassLoader
(およびそのサブクラス)のコンストラクターを使用すると、新しいクラスローダーをインスタンス化するときに親を指定できます。明示的に親を指定しない場合、仮想マシンのシステムクラスローダーがデフォルトの親として割り当てられます。つまり、ClassLoaderクラスは委任モデルを使用してクラスとリソースを検索します。したがって、ClassLoaderの各インスタンスには親クラスローダーが関連付けられているため、クラスまたはリソースを検索するように要求されると、クラスまたはリソース自体を検索する前に、タスクは親クラスローダーに委任されます。loadClass()
ClassLoader のメソッドは、クラスをロードするために呼び出されると、次のタスクを順番に実行します。
クラスがすでにロードされている場合は、それを返します。それ以外の場合は、新しいクラスの検索を親クラスローダーに委任します。親クラスローダーがクラスを見つけられない場合loadClass()
は、メソッドfindClass()
を呼び出してクラスを見つけてロードします。このfinalClass()
メソッドは、親クラスローダーによってクラスが見つからなかった場合、現在のクラスローダーでクラスを検索します。
オリジナルの記事には、独自のネットワーククラスローダーを実装する方法も記載されており、理由(および方法)に関する質問に答えています。APIドキュメントもご覧ください。