web-dev-qa-db-ja.com

Class.forName()vs ClassLoader.loadClass()-動的ロードに使用するのはどれですか?

クラスを動的にロードするとき、いつ使用するのが適切か

Class.forName("SomeClass");

いつ使うべきですか

ClassLoader.getSystemClassLoader().loadClass("SomeClass");

または、同じことを行う2つの方法ですか?

97
Zack

それらは全く違います!

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");)は以下を行います:

  • 「システム」クラスローダーを使用します( オーバーライド可能
  • クラスを初期化しない(たとえば、JDBCドライバーのロードに使用すると、登録されず、JDBCを使用できなくなります!)

Tomcatなどのコンテナで実行されるWebアプリケーションをコーディングしているとします。 Tomcatは、Webアプリケーションごとにクラスローダーを作成します(Webアプリケーションを後でアンロードしてメモリを解放できるように、これを機能させるには専用のクラスローダーが必要です!)。この状況では、両方の呼び出しでまったく異なる結果が得られることがわかります!

クラスのロードと初期化に関する詳細な(および信頼できる)情報については、Java言語の最新(第3)版のセクション 12.2 および 12.4 を確認してください。仕様。

147
Bruno Reis

Class.forName()は、呼び出し元のクラスローダーを使用して、クラスを初期化します(静的初期化プログラムなどを実行します)

loadClassClassLoaderメソッドであるため、明示的に提供されたローダーを使用し、クラスを遅延的に初期化します(最初の使用時)。

Class.forName() があり、これもClassLoaderを取ることに注意してください。

8
Dave Newton

彼らは基本的に同じことをしています。ただし、使用されるClassLoaderは異なる場合があります。 Class.forNameはthis.getClass()。getClassLoader()から取得したClassLoaderを使用しますが、他のコードはシステムクラスローダーの使用を指定します。

ほとんどのアプリケーションでは、これは同じクラスローダーになりますが、J2EEアプリやアプレットなどのより複雑な環境では、そうではない場合があります。

1
Sarel Botha

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

0
r0ast3d
  • 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
0
Premraj