我是java Reflection / Dynamic Loading的初学者。我想从jar-File加载一个特定的类(实现一个接口)。此外,我想初始化此类的Object并将其转换为我的特定接口。
我尝试了.loadClass()
,class.forName()
,如果我将Myclass.newInstance
投射到我的界面,我将获得ClassCastException。
我如何编程我的插件-Lader,所以它将我的类加载到我的jar中并将其转换为myInterface
?
我的服务器与我的插件工具具有相同的界面。现在我希望我的插件“加载”并投射到我的界面,以便我可以正常使用它们。
以下是我试图摆脱这些错误的一些示例代码:D
URL url = f.toURL();
URL[] urls = new URL[]{url};
ClassLoader cl = new URLClassLoader(urls);
Class<ModInterface> c = (Class<ModInterface>)cl.loadClass("com.myapp.mod");
Class<? extends ModInterface> sub = c.asSubclass(ModInterface.class);
Constructor<? extends ModInterface> con = sub.getConstructor();
ModInterface mi = con.newInstance();
我已完成的另一个代码示例:
ClassLoader loader = PluginLoader.class.getClassLoader();
URL url = new URL("jar:file:" + f.getAbsolutePath() + "!/");
URLClassLoader ucl = new URLClassLoader(new URL[] { url }, loader);
Class iInterfaceClass = Class.forName("com.myapp.mod", true, ucl);
ModInterface mi = (ModInterface) iInterfaceClass.newInstance();
java.lang.ClassCastException: com.myapp.mod cannot be cast to myapp.ModInterface
在您提供的一些帮助后,我完成了以下操作:
URL url = f.toURI().toURL();
URL[] urls = new URL[]{url};
ClassLoader loader = ModInterface.class.getClassLoader();
ClassLoader cl = new URLClassLoader(urls, loader);
Class<?> loadedClass = Class.forName("com.myapp.mod", true, cl);
Class<? extends ModInterface> pluginClass = loadedClass.asSubclass(ModInterface.class);
ModInterface mi = pluginClass.newInstance();
现在我收到此错误 - &gt; java.lang.ClassCastException:类com.myapp.mod在loadedClass.asSubclass(..)中抛出; 找到特定的类,因为如果我将com.myapp.mod更改为它会抛出一个classnotfound execption。我试过使用ModInterface ClassLoader,但没有改变。 (out)我会得到同样的错误。
注意:// 我用2个项目。 1为我的服务器应用程序,另一个为我的插件应该加载。两者都有相同的界面。
编辑://
使用此代码我从我想要的类中获取Object类型的Object,但它不是我的ModInterface的实例,尽管我的类实现了我的ModInterface。如果我尝试将我的对象转换为我的ModInterface,则会出现错误。这是我的简短代码:
Class c = clazzLoader.loadClass(element.getName().replaceAll(".class", "").replaceAll("/", "."));
Object instance = c.newInstance();
答案 0 :(得分:1)
您似乎知道实现接口的类的具体名称,并且必须进行实例化。在这种情况下,以下内容将起作用:
考虑以下界面
package test.api;
public interface Plugin {
void service();
}
具有以下实现
package test.impl;
import test.api.Plugin;
public class PluginImpl implements Plugin {
@Override
public void service() {
System.out.println(":-)");
}
}
然后以下代码片段将执行您想要的操作(并打印出“:-)”):
Class<?> loadedClass = Class.forName("test.impl.PluginImpl");
Class<? extends Plugin> pluginClass = loadedClass.asSubclass(Plugin.class);
Plugin plugin = pluginClass.newInstance();
plugin.service();
您还可以使用适当的类加载器来获取正确的类引用(就像您在代码示例中所做的那样)。
请注意,Class.forName
会返回Class<?>
,之后必须投放Class.asSubClass
。使用ClassCastException
可以更好地完成此演员表。如果加载的类没有实现接口,那么您将获得{{1}}。
然而......如果你想建立一个简单的插件机制,你应该考虑使用ServiceLoader,这需要你的可插拔JAR来定义服务配置文件。有关详细说明,请参阅链接。
BTW:您的代码示例中要加载的类看起来更像是包名,因此无法找到它。也许这是你的问题?
答案 1 :(得分:0)
好吧,您似乎想要动态加载interface
说A
,以及实施class
说B
。你可以通过反思来做到:
Class<?> bClass = Class.forName("packagename.B", true, loader);
Class<?> aClass = Class.forName("packagename.A", true, loader);
Object bObject = // create an instance of class B via Reflection
Object aObject = aClass.cast(bobject);
请记住,两个类定义都必须从类加载器加载,类加载器是两者的共同父类。演员在这里服务的唯一目的是确定B
确实是A
的子类型。
将对象强制转换为此Class对象所代表的类或接口。
Reflection tutorial将帮助您了解锄头以反射性地创建实例。
答案 2 :(得分:0)
我自己解决了我的问题。我已经完成了一个集成了我的ModInterface的客户端库。之后我将.jar添加到我的Projects中,因此两者都具有相同的Modinterface-Base。在此步骤之后,可以使用ClassLoader.LoadClass而不使用任何Casting-Exceptions。
感谢您的帮助