加载类,生成此类的对象

时间:2013-07-22 12:42:26

标签: java class dynamic reflection classcastexception

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

3 个答案:

答案 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)

好吧,您似乎想要动态加载interfaceA,以及实施classB。你可以通过反思来做到:

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#cast()

  

将对象强制转换为此Class对象所代表的类或接口。

Reflection tutorial将帮助您了解锄头以反射性地创建实例。

答案 2 :(得分:0)

我自己解决了我的问题。我已经完成了一个集成了我的ModInterface的客户端库。之后我将.jar添加到我的Projects中,因此两者都具有相同的Modinterface-Base。在此步骤之后,可以使用ClassLoader.LoadClass而不使用任何Casting-Exceptions。

感谢您的帮助