72

プロパティファイルにクラス名を保存しています。クラス ストアが IDynamicLoad を実装することはわかっています。クラスを動的にインスタンス化するにはどうすればよいですか?

今、私は持っています

     Properties foo = new Properties();
    foo.load(new FileInputStream(new File("ClassName.properties")));
    String class_name = foo.getProperty("class","DefaultClass");
    //IDynamicLoad newClass = Class.forName(class_name).newInstance();

newInstance はコンパイルされた .class ファイルのみをロードしますか? コンパイルされていない Java クラスをロードするにはどうすればよいですか?

4

3 に答える 3

146

コンパイルされていないJavaクラスをロードするにはどうすればよいですか?

最初にコンパイルする必要があります。これは、javax.toolsAPIを使用してプログラムで実行できます。これには、JREの上にあるローカルマシンにJDKをインストールするだけで済みます。

基本的なキックオフの例を次に示します(明らかな例外処理は別として):

// Prepare source somehow.
String source = "package test; public class Test { static { System.out.println(\"hello\"); } public Test() { System.out.println(\"world\"); } }";

// Save source in .java file.
File root = new File("/java"); // On Windows running on C:\, this is C:\java.
File sourceFile = new File(root, "test/Test.java");
sourceFile.getParentFile().mkdirs();
Files.write(sourceFile.toPath(), source.getBytes(StandardCharsets.UTF_8));

// Compile source file.
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
compiler.run(null, null, null, sourceFile.getPath());

// Load and instantiate compiled class.
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { root.toURI().toURL() });
Class<?> cls = Class.forName("test.Test", true, classLoader); // Should print "hello".
Object instance = cls.newInstance(); // Should print "world".
System.out.println(instance); // Should print "test.Test@hashcode".

これは次のようになります

hello
world
test.Test@ab853b

implementsそれらのクラスがすでにクラスパスにある特定のインターフェースである場合、さらに使用するのはより簡単です。

SomeInterface instance = (SomeInterface) cls.newInstance();

それ以外の場合は、(不明な)メソッド/フィールドにアクセスして呼び出すためにReflectionAPIを使用する必要があります。


そうは言っても、実際の問題とは無関係です。

properties.load(new FileInputStream(new File("ClassName.properties")));

現在の作業ディレクトリjava.io.Fileに依存させることは、移植性の問題のレシピです。そうしないでください。そのファイルをクラスパスに入れ、ClassLoader#getResourceAsStream() クラスパス相対パスで使用します。

properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("ClassName.properties"));
于 2010-05-31T23:11:03.390 に答える
6

BalusCの答えと同じですが、私のkilimディストリビューションのこのコードには、もう少し自動ラッパーがあります。 https://github.com/kilim/kilim/blob/master/src/kilim/tools/Javac.java

Javaソースを含む文字列のリストを取得し、パッケージ名とパブリッククラス/インターフェイス名を抽出し、対応するディレクトリ/ファイル階層をtmpディレクトリに作成します。次に、Javaコンパイラを実行し、名前とクラスファイルのペアのリスト(ClassInfo構造)を返します。

コードを手伝ってください。MITライセンスです。

于 2011-10-07T03:14:17.850 に答える
5

クラスに引数なしのパブリックコンストラクターがあることがわかっている場合、コメントされたコードは正しいです。コンパイラはクラスが実際にを実装することを知ることができないため、結果をキャストする必要がありますIDynamicLoad。それで:

   IDynamicLoad newClass = (IDynamicLoad) Class.forName(class_name).newInstance();

もちろん、それが機能するためには、クラスがコンパイルされ、クラスパス上にある必要があります。

ソースコードからクラスを動的にコンパイルすることを検討している場合、それはまったく別の魚のやかんです。

于 2010-05-31T23:03:33.067 に答える