Пример Java с ClassLoader

У меня небольшая проблема. Я изучаю java SE и нахожу класс ClassLoader. Я пытаюсь использовать его в приведенном ниже коде: я пытаюсь использовать URLClassLoader для динамической загрузки класса во время выполнения.

URLClassLoader urlcl = new URLClassLoader(new URL[] {new URL("file:///I:/Studia/PW/Sem6/_repozytorium/workspace/Test/testJavaLoader.jar")});
Class<?> classS = urlcl.loadClass("michal.collection.Stack");
for(Method field: classS.getMethods()) {
     System.out.println(field.getName());
}
Object object = classS.newInstance();
michal.collection.Stack new_name = (michal.collection.Stack) object;

Виртуальная машина Java не видит мой класс, и я получаю следующее исключение:

Exception in thread "main" java.lang.Error: Unresolved compilation problems: michal cannot be resolved to a type michal cannot be resolved to a type at Main.main(Main.java:62)

Вы знаете, как я могу решить эту проблему?


person Michał    schedule 13.03.2012    source источник
comment
Можете ли вы опубликовать полученное исключение и трассировку стека?   -  person Shaunak    schedule 14.03.2012
comment
Конечно: Исключение в потоке main java.lang.   -  person Michał    schedule 14.03.2012


Ответы (3)


Class<?> classS = urlcl.loadClass("michal.collection.Stack");
[...]
Object object = classS.newInstance();
michal.collection.Stack new_name = (michal.collection.Stack) object;

Итак, вы пытаетесь динамически загрузить класс, а затем статически ссылаетесь на него. Если вы уже можете статически связать его, то он загружен, и вы не можете загрузить его снова. Вам нужно будет получить доступ к методам путем отражения.

Обычно вы делаете так, чтобы загружаемый класс реализовывал интерфейс из загрузчика родительского класса. После того, как экземпляр создан (обычно только один экземпляр), вы можете обратиться к нему через ссылку с типом интерфейса.

public interface Stack {
   [...]
}
[...]
    URLClassLoader urlcl = URLClassLoader.newInstance(new URL[] {
       new URL(
           "file:///I:/Studia/PW/Sem6/_repozytorium/workspace/Test/testJavaLoader.jar"
       )
    });
    Class<?> clazz = urlcl.loadClass("michal.collection.StackImpl");
    Class<? extends Stack> stackClass = clazz.asSubclass(Stack.class);
    Constructor<? extends Stack> ctor = stackClass.getConstructor();
    Stack stack = ctor.newInstance();

(Обычный отказ от ответственности за переполнение стека не столько о компиляции.)

Вам нужно будет добавить обработку ошибок по вкусу. URLClassLoader.newInstance добавляет немного изысканности к URLClassLoader. Class.newInstance полностью нарушает обработку исключений, и его следует избегать.

person Tom Hawtin - tackline    schedule 13.03.2012
comment
Итак, как я могу использовать метод из этого класса? - person Michał; 14.03.2012
comment
@user1267483 user1267483 Вам нужно будет создать интерфейс в проекте, который вы используете URLClassloader для стека, который реализует ваш michal.collection.Stack. - person Jacob Schoen; 14.03.2012
comment
@user1267483 user1267483 Обратите внимание, я изменил имя Stack на StackImpl (не лучшее имя, но обычное) и представил новый интерфейс, Stack. - person Tom Hawtin - tackline; 14.03.2012
comment
Я понимаю. Большое спасибо за помощь. У меня была вторая проблема, потому что мой класс Stack является шаблоном, но я сам решаю эту проблему. - person Michał; 14.03.2012

Оба приведенных выше ответа неверны, они не понимают корневой проблемы. Ваш main относится к классу Stack, который был загружен одним загрузчиком классов. Ваш urlclassloader пытается загрузить класс с тем же именем. Вы не можете приводить загруженные к указанным, потому что они не совпадают, они принадлежат разным загрузчикам классов. Вы можете распечатать код каждого из них, чтобы увидеть, что они разные. Проверка на равенство также покажет, что ссылки cclass отличаются. Ваша проблема, вероятно, связана с тем, что могут быть найдены зависимые классы, на которые ссылается sstack, которые будут rsukt в NoClassDefErrors и т. д. Ваш main, вероятно, завершится ошибкой с classcastException.

person mP.    schedule 15.03.2012

Вы не можете ссылаться на динамически загружаемый тип по имени в коде, так как это должно быть разрешено во время компиляции. Вам нужно будет использовать функцию newInstance() объекта Class, который вы получите от loadClass().

person VeeArr    schedule 13.03.2012
comment
OP использует Class.newInstance для объекта Class из loadClass. - person Tom Hawtin - tackline; 14.03.2012