Позвольте мне сначала подвести итог, что именно я пытаюсь сделать. По сути, я использую пакет JavaCompiler для компиляции класса во время выполнения, который расширяет мой суперкласс "Player". Единственное, что я знаю, будет в подклассе, это то, что он расширит Player и переопределит абстрактный метод calcMove (). Чтобы загрузить класс во время выполнения после его компиляции, я создаю объект URIclassloader для загрузки файла класса после того, как он был создан. Проблема в том, что когда я пытаюсь запустить метод calcMove из экземпляра объекта (используя java.lang.reflect)
Вот что я делаю в основном:
//to hold the compiler output
ByteArrayOutputStream compilerOut = new ByteArrayOutputStream();
//compile
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
int compilationResult = compiler.run(null, compilerOut, compilerOut, playerFile.getAbsolutePath());
if (compilationResult == 0) {
System.out.println("File " + playerFile.getName() + " compiled successfully");
} else {
//code 99 as compile error
System.err.println(compilerOut.toString());
System.exit(99);
}
Как толькофайл скомпилирован, я использую этот код, чтобы сделать загрузчик классов для загрузки класса (папка загрузки содержит исходные файлы и файлы классов). Имя_класса определяется по имени файла. Затем я использую java Reflection, чтобы создать экземпляр класса как объекта и привести его в качестве Player:
URL classUrl = new File("upload").toURI().toURL();
ClassLoader classLoader = URLClassLoader.newInstance(new URL[]{classUrl}, ClassLoader.getSystemClassLoader());
classLoader.loadClass(className).asSubclass(Player.class);
Class<?> studentCustomClass = Class.forName(className, true, classLoader);
Constructor<?> constructor = studentCustomClass.getConstructor();
Player studentPlayer = (Player) constructor.newInstance()
Создание экземпляра, очевидно, работает, пока я не доберусь до места, где он вызывает calcMove. Я создаю новый класс "Game", который принимает 2 аргумента Player, в этом классе Game я вызываю метод calcMove () из объектов пользовательского класса (разыгрываемых как Players). Однако я получаю исключение AbstractMethodError, потому что он пытается вызвать абстрактный метод calcMove из Player вместо реализованной версии из подкласса.
Итак, мне интересно, есть ли какая-то причина, почему он пытается вызватьабстрактная версия из родительского класса вместо версии из класса, который я только что скомпилировал? (Насколько я могу судить, java рассматривает созданный мною объект как тип класса подкласса, а не просто класс Player, который я не смог создать в любом случае с момента его абстракции). Сейчас я использую java Reflection, чтобы заставитьчтобы вызвать функцию calcMove из объекта
Method calcmove = players[0].getClass().getMethod("calcMove");
calcmove.invoke(players[0]);
Я бы не хотел использовать отражение в этой точке кода из соображений безопасности. Так почему же это работает, но это:
players[0].calcMove();
Дает мне AbstractClassError?