class.forNameの使用法を理解するのに苦労しています。実際、私はプロジェクトに取り組んでおり、文字列を受け入れるフィールドがあります。クラスパス!この文字列をclass.forNameに渡します-例外はありません...したがって、class.forNameは指定されたクラスを見つけることができます。その後、指定されたクラスを呼び出します。しかし、ここに私の問題があります。まず、クラスの名前を取得するために文字列を分離する必要があります...そうですか?また、これ
を行うClass requestedClass = Class.forName(path);
AClass newClassInstance = (AClass)requestedClass.newInstance();
と、クラスのコンストラクターでいくつかのパラメーターを渡す必要があるため、例外InstantiationExceptionが発生します。これに対する解決策はありますか?ifステートメントを使用してそれぞれのクラスを呼び出す方が賢明に聞こえますが、可能なクラスが多数ある場合、このアプローチは悪夢になります。ありがとうございました!
4 に答える
コードのコンパイル時に存在しなかったロードするクラスを指定できるので便利です。HTMLのapplet
タグは、これを使用してのサブクラスをロードしますjava.applet.Applet
。Webサーバーはこれを使用して、Javaサーブレットおよびその他のWebコンポーネントをロードします。EJBコンテナ、Springコンテナ、およびその他の多くのプログラムは、このメソッドを使用してコンポーネントをロードします。EclipseまたはNetBeansを使用する場合、これらのIDEはを使用してプラグClass.forName()
インをロードします。これにより、毎日作成される新しいプラグインをロードできます。
この魔法のすべての鍵は継承`です。作成されたオブジェクトをインターフェイスまたは親クラスのインスタンスとして扱うことができる必要があります。つまり、
Applet applet = (Applet) Class.forName(theNameOfSomeAppletClass).newInstance();
次にtheNameOfSomeAppletClass
、コードが聞いたことがない場合でも、HTMLファイル(たとえば)から読み取り、クラスのインスタンスを作成できます。
ほとんどの場合、プラグインAPIは、プラグインクラスに引数なしのコンストラクターを指定するように指定するだけです。ただしjava.lang.Class
、オブジェクトgetConstructors()
を取得できるメソッドがあります。これによりConstructor
、本当に必要な場合は、コンストラクターに引数を渡すことでクラスをインスタンス化できます。
これに見られるもう1つの大きな用途は、JDBCドライバーのロードです。これはおそらく、ほとんどのJavaプログラマーが遭遇するClass.forNameの最初の使用法です。表示されるのはこれです:
Class.forName("oracle.jdbc.OracleDriver");
Connection connection = DriverManager.getConnection("jdbc:oracle:thin:...");
ここで何が起こるかというと、OracleDriverクラスが(Class.forNameを介して)ロードされると、このようなクラス初期化ブロックが含まれます(おそらくもっと複雑ですが、要点を示しています)。このブロックは、クラスの読み込みプロセスの一部として実行されます。
public class OracleDriver {
static {
DriverManager.registerDriver(new OracleDriver());
}
}
次に、DriverManager.getConnectionを呼び出すと、登録されているすべてのドライバーに、指定されたURLを処理できるかどうかを尋ねることができます(コードはより複雑ですが、少し簡略化します)。
for (Driver driver : registeredDrivers) {
if (driver.acceptsURL(url)) {
// use this driver
}
}
インスタンス化の問題に関する限り、Class.newInstance()メソッドは常に引数なしのコンストラクターを呼び出し、存在しない場合は例外をスローします。特定のコンストラクターが必要な場合は、クラス自体で「getConstructor」メソッドを使用します。たとえば、StringとLongを受け取るコンストラクターが必要な場合:
Class clazz = ...; // figure out which class here
Constructor c = clazz.class.getConstructor(String.class, Long.class);
Object o = c.newInstance("foo", new Long(1L));
指摘されているように、プラグインや拡張機能など、コンパイル時に存在しなかったクラスをロードできるため、非常に便利です。
あなたの問題には簡単な解決策があります。検索しているコンストラクターを単純にフェッチし、期待される引数を指定します。例えば:
MyClass a = (MyClass) Class.forName("com.test.MyClass")
.getConstructor(new Class[] { String.class }).newInstance("Test");
次を使用して、リフレクションを介してパラメーター化されたコンストラクターを呼び出すことができますClass.getConstructor()
。
class Foo {
public Foo(String bar) {
System.out.println("bar = " + bar);
}
}
Class<?> fooCls = Class.forName("Foo");
Constructor<?> fooCtor = fooCls.getConstructor(String.class);
Foo foo = (Foo) fooCtor.newInstance("BAR");
インスタンス化する必要のあるクラスに引数なしのコンストラクターがなく、クラスに渡すパラメーターがわからない場合は、運が悪いことになります。(これも設計の重大な欠陥になります。メソッドがN個のクラスから1つをインスタンス化する必要がある場合は、コンストラクター署名であろうとファクトリメソッドであろうと、すべてのクラスを同じ方法でインスタンス化できるはずです。)