AbstractMethodError при вызове переопределенного метода абстрактного класса из класса, скомпилированного во время выполнения - PullRequest
0 голосов
/ 04 ноября 2019

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

1 Ответ

0 голосов
/ 08 ноября 2019

Мне удалось найти решение, которое работает. Если я объявляю абстрактный метод calcMove в Player защищенным, то он должным образом использует calcMove из подкласса без использования отражения для его принудительной установки. Я предполагаю, что это потому, что он не может вызвать защищенный метод в Player, поэтому он вызывает метод доступа public / package в подклассе (поскольку переопределенные методы могут иметь более высокий уровень видимости, чем метод, который они переопределяют, я обнаружил)Я не совсем уверен, почему это работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...