Вопрос по reflection, dynamic-loading, java – Как программно скомпилировать и создать экземпляр класса Java? [Дубликат]

63

На этот вопрос уже есть ответ здесь:

Как вы динамически компилируете и загружаете внешние Java-классы? [Дубликат] 2 ответа

У меня есть имя класса хранится в файле свойств. Я знаю, что магазин классов будет реализовывать 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, который не скомпилирован?

Ваш Ответ

1   ответ
128

Вы должны сначала скомпилировать его. Это можно сделать программно с помощьюjavax.tools API, Это требует толькоJDK устанавливается на локальном компьютере поверх JRE.

Вот основной пример запуска (оставляя в стороне очевидную обработку исключений):

// 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 "[email protected]".

Который дает как

hello
world
[email protected]

Дальнейшее использование будет проще, если эти классыimplements определенный интерфейс, который уже находится в пути к классам.

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

В противном случае вам нужно привлечьReflection API получить доступ и вызвать (неизвестные) методы / поля.

Это говорит и не имеет отношения к актуальной проблеме:

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

Позволитьjava.io.File полагаться на текущую рабочую директорию - рецепт проблем с переносимостью. Не делай этого. Поместите этот файл в classpath и используйтеClassLoader#getResourceAsStream() с относительным путем к классу пути.

properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("ClassName.properties"));
Кроме того, вы должны использовать сгенерированный, независимый от системы временный каталог для корня, например, черезFile root = Files.createTemporaryDirectory(null).toFile(). Raffi Khatchadourian
Files.write(source, sourceFile, StandardCharsets.UTF_8); не компилируется для меня. Я думаю ты хочешьFiles.write(sourceFile.toPath(), source.getBytes());. Raffi Khatchadourian
Просто не по теме вопрос. Я получаю нулевое значение, когда я загружаю свойства по-вашему, но я получаю свойства, когда я делаю это Foo.class.getResourceAsStream ()? Не могли бы вы помочь мне понять ваш код? Спасибо. unj2
@BalusC: Извините, если я избыточен, но могу ли я указать classpath перед компиляцией файла Java? Если это так, понадобится ваше руководство. Nilesh

Похожие вопросы