我有一个实现ToTest接口的MyClass类,我希望通过在Tomcat上运行的Web App中的ClassLoader来检索。
课程如下:
public class MyClass implements ToTest {
public String doStuff(String input) {
return null;
}
}
,界面是
public interface ToTest {
public String doStuff(String input);
}
当我实例化类的正常实例时,它正常工作(即看起来是ToTest的一个实例),但是,当我使用我的类加载器时,该对象不会解析为ToTest的实例。
即
Object myObject = new MyClass();
if (myObject instanceof ToTest) {
System.out.println("This is a ToTest");
}
将打印出消息,而:
URLClassLoader classLoader = new URLClassLoader(new URL[]{new File("c:\\tomcatfolder\\wtpwebapps\\MyApp\\WEB-INF\\classes").toURI().toURL()});
Class<?> loadedClass = classLoader.loadClass("MyClass");
Object myOtherObj = loadedClass.newInstance();
if (myOtherObj instanceof ToTest) {
System.out.println("This is a ToTest");
}
返回一个看似是MyClass对象的对象,但是&#39; if instanceof&#39;返回false。
有什么想法吗?
由于
答案 0 :(得分:2)
这是因为如果你使用不同的类加载器加载相同的类,它被认为是一个不同的类。人们甚至可以简化你的问题:
URLClassLoader classLoader = new URLClassLoader(new URL[]{new File("c:\\tomcatfolder\\wtpwebapps\\MyApp\\WEB-INF\\classes").toURI().toURL()});
Class<MyClass> loadedClass = classLoader.loadClass("MyClass");
Object myOtherObj = loadedClass.newInstance(); //loaded by URLClassLoader
Object myObject = new MyClass(); // loaded by default classloader
// at this point the two objects don't have the same type
如果我们查看您的实际问题,我们会看到myOtherObj
是从与您比较的ToTest
不同的类加载器加载的。这意味着它的类MyClass
没有实现与用于比较的ToTest
相同的URLClassLoader classLoader = new URLClassLoader(new URL[]{new File("c:\\tomcatfolder\\wtpwebapps\\MyApp\\WEB-INF\\classes").toURI().toURL()}, getClass().getClassLoader());
。
来自JLS:
“在运行时,具有相同二进制名称的几个引用类型可以由不同的类加载器同时加载。这些类型可能表示也可能不表示相同的类型声明。即使两个这样的类型确实表示相同的类型声明,它们被认为是截然不同的。“
和
“两个引用类型是相同的运行时类型,如果[...]它们都是类或两种接口类型,由相同的类加载器定义,并具有相同的二进制名称[...]”< / p>
正如bmargulies指出的那样,你可以通过将当前的类加载器设置为自定义类的父类来避免这种情况:
{{1}}
答案 1 :(得分:1)
您没有将新的类加载器设置为从旧的类加载器继承。因此,它不与您现有的类加载器共享任何类。因此,从类加载器中反射创建的对象将不会成为任何类的实例。
我不明白为什么你会想要这个类加载器,但如果你需要设置父类。