クラスを動的にロードするとき、いつ使用するのが適切か
Class.forName("SomeClass");
いつ使うべきですか
ClassLoader.getSystemClassLoader().loadClass("SomeClass");
または、同じことを行う2つの方法ですか?
それらは全く違います!
Class.forName(String)
のドキュメントに記載されているように、
指定された文字列名を持つクラスまたはインターフェースに関連付けられたClassオブジェクトを返します。このメソッドを呼び出すことは、次と同等です:
Class.forName(className, true, currentLoader)
(true
はここでを指します。クラスを初期化しますか?)
一方、 ClassLoader.loadClass(String)
:
このメソッドを呼び出すことは、
loadClass(name, false)
を呼び出すことと同等です。
(ここでは、ブール値は初期化とは関係ありませんが、loadClass(String、boolean)のドキュメントを確認すると、クラスを初期化するのではなくクラスをロードするだけであることがわかります)。
最初のもの(Class.forName("SomeClass");
)は以下を行います:
他の(ClassLoader.getSystemClassLoader().loadClass("SomeClass");
)は以下を行います:
Tomcatなどのコンテナで実行されるWebアプリケーションをコーディングしているとします。 Tomcatは、Webアプリケーションごとにクラスローダーを作成します(Webアプリケーションを後でアンロードしてメモリを解放できるように、これを機能させるには専用のクラスローダーが必要です!)。この状況では、両方の呼び出しでまったく異なる結果が得られることがわかります!
クラスのロードと初期化に関する詳細な(および信頼できる)情報については、Java言語の最新(第3)版のセクション 12.2 および 12.4 を確認してください。仕様。
Class.forName()
は、呼び出し元のクラスローダーを使用して、クラスを初期化します(静的初期化プログラムなどを実行します)
loadClass
はClassLoader
メソッドであるため、明示的に提供されたローダーを使用し、クラスを遅延的に初期化します(最初の使用時)。
Class.forName() があり、これもClassLoader
を取ることに注意してください。
彼らは基本的に同じことをしています。ただし、使用されるClassLoaderは異なる場合があります。 Class.forNameはthis.getClass()。getClassLoader()から取得したClassLoaderを使用しますが、他のコードはシステムクラスローダーの使用を指定します。
ほとんどのアプリケーションでは、これは同じクラスローダーになりますが、J2EEアプリやアプレットなどのより複雑な環境では、そうではない場合があります。
ClassLoaderは抽象クラスですが、アプリケーションは常にクラスローダーによってロードされます。ネットワーククラスローダーやその他のソースなどのカスタムクラスローダーが存在する可能性があります。
一方、クラス自体はクラスとインターフェイスを表し、クラスクラスにはforName関数があり、デフォルトでアプリケーションが実行されている現在のクラスローダーを使用してクラスをロードします。
次に、呼び出し元のクラスローダーを呼び出すClass.forNameのソースを示します。
public static Class<?> forName(String className)
throws ClassNotFoundException {
return forName0(className, true, ClassLoader.getCallerClassLoader());
}
http://docs.Oracle.com/javase/1.4.2/docs/api/Java/lang/ClassLoader.html
http://docs.Oracle.com/javase/1.5.0/docs/api/Java/lang/Class.html#forName(Java.lang.String )
ヒント:Primordial class loader http://docs.Oracle.com/javase/1.4.2/docs/guide/security/spec/security-spec.doc5.html
Class.forName()
クラスをロードして初期化します。クラスローダーサブシステムでは、3つのフェーズ(ロード、リンク、初期化の各フェーズ)をすべて実行します。
ClassLoader.loadClass()
動作。クラスが初めて使用されるまで初期化を遅らせます。クラスローダーサブシステムでは、ロードフェーズとリンクフェーズの2つのフェーズのみを実行します。
例えば:
class MyClass {
static {
System.out.println("static block in MyClass");
}
}
public class TestCase1 {
public static void main(String... args) throws Throwable {
Class.forName("A");
}
} //The above TestCase1 produce output: static block in MyClass
public class TestCase2 {
public static void main(String... args) throws Throwable {
ClassLoader.getSystemClassLoader().loadClass("MyClass");
}
} //The above TestCase2 not produce any output