Michał
Michał

Reputation: 143

Java example with ClassLoader

I have small problem. I learn java SE and find class ClassLoader. I try to use it in below code: I am trying to use URLClassLoader to dynamically load a class at runtime.

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;

The java virtual machine does not see me class, and I get the following exception:

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)

Do you know how I can solve this problem?

Upvotes: 7

Views: 26071

Answers (3)

mP.
mP.

Reputation: 18266

The above answers are both wrong, they don't understand the root problem. Your main refers to the Stack class which was loaded by one class loader. Your urlclassloader is attempting to load a class with the same name. You cannot cast the loaded to the referred because they are not the same, they belong to different classloaders. You can print the has code of each to see they are different. An equality test will also show the cclass references to be different. Your problem is probably because dependent classes referenced by sstack can be found, which will result in NoClassDefErrors etc. Your main will probably fail with a classcastexception.

Upvotes: 4

Tom Hawtin - tackline
Tom Hawtin - tackline

Reputation: 147144

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

So you're attempting to dynamically load a class and then you statically refer to it. If you can already statically link to it, then its loaded and you can't load it again. You'll need to access the methods by reflection.

What you would usually do is have the loaded class implement an interface from the parent class loader. After an instance is created (usually just a single instance), then you can refer to it through a reference with a type of the interface.

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();

(Usual Stack Overflow disclaimer about not so much as compiling.)

You'll need to add error handling to taste. URLClassLoader.newInstance adds a bit of refinement to URLClassLoader. Class.newInstance has completely broken exception handling and should be avoided.

Upvotes: 2

VeeArr
VeeArr

Reputation: 6178

You can't refer to the dynamically-loaded type by name in the code, since that has to be resolved at compile-time. You'll need to use the newInstance() function of the Class object you get back from loadClass().

Upvotes: 0

Related Questions