1. ホーム
  2. java

[解決済み] Java ClassLoaderとは何ですか?

2022-04-30 21:15:52

質問

Java ClassLoaderとは何か、どのような場合に使用され、なぜ使用されるのか、簡単な文章で説明してください。

OK、wikiの記事を読みました。ClassLoaderはクラスをロードします。OKです。jarファイルをインクルードしてインポートすれば、ClassLoaderが仕事をするわけだ。

なぜわざわざこのClassLoaderを使う必要があるのでしょうか?使ったこともないし、存在も知らなかった。

問題は、なぜClassLoaderクラスが存在するのか、ということです。そしてまた、実際にどのように使うのか?(ケースは存在しますよね)。

どのように解決するのか?

この素敵な作品から引用 チュートリアル を紹介しました。

モチベーション

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に変更されたことからも明らかです。

JDK1.2以降では、JVMに組み込まれたブートストラップ・クラス・ローダーが、Javaランタイムのクラスの読み込みを担当する。このクラスローダーは、ブートクラスパスにあるクラスのみをロードし、これらは信頼できるクラスであるため、信頼できないクラスに対するような検証処理は行われない。ブートストラップ・クラス・ローダーの他に、JVMは標準的な拡張APIからクラスをロードする責任を負う拡張クラス・ローダーと、あなたのアプリケーション・クラスと同様に一般的なクラス・パスからクラスをロードするシステム・クラス・ローダーを持っています。

クラスローダーは複数存在するため、ブートストラップ・クラスローダーをルートとするツリーで表現されます。各クラス・ローダーは、その親クラス・ローダーへの参照を持っています。クラス・ローダーは、クラスをロードするように要求されると、それ自体をロードしようとする前に、その親クラス・ローダーに問い合わせます。親は今度はその親を参照し、といった具合です。つまり、すべての祖先クラス・ローダーがクラスを見つけられなかった場合にのみ、現在のクラス・ローダーが関与することになるのです。つまり、デリゲーションモデルが使用されているのです。

java.lang.ClassLoaderクラス

を使用します。 java.lang.ClassLoader は抽象クラスで、JVMがクラスを動的にロードする方法を拡張する必要があるアプリケーションによってサブクラス化することができます。のコンストラクタは java.lang.ClassLoader (およびそのサブクラス) では、新しいクラス・ローダーのインスタンスを作成するときに親を指定することができます。明示的に親を指定しない場合、仮想マシンのシステム・クラス・ローダーがデフォルトの親として割り当てられます。つまり、ClassLoader クラスは、クラスとリソースを検索するためにデリゲーション・モデルを使用します。したがって、ClassLoader の各インスタンスには関連する親クラス・ローダーがあり、クラスやリソースの検索を要求されると、クラスやリソースを自ら検索しようとする前に、そのタスクが親クラス・ローダーに委譲されるようになっています。そのため loadClass() メソッドは、クラスをロードするために呼び出されると、以下のタスクを順番に実行します。

クラスがすでにロードされている場合は、それを返します。 そうでない場合は、新しいクラスの検索を親クラス・ローダーに委ねます。 親クラス・ローダーがクラスを見つけられなかった場合は、次のようになります。 loadClass() メソッドを呼び出します。 findClass() を使用して、クラスを検索してロードします。 その際 finalClass() メソッドは、親クラスローダーでクラスが見つからなかった場合に、 現在のクラスローダーでクラスを検索します。


元記事にはさらに、独自のネットワーク・クラス・ローダーを実装する方法も紹介されており、なぜ(どのように)かという質問に答えてくれています。また APIドキュメント .