0

我是java反射/动态加载的初学者。我想从 jar 文件中加载一个特定的类(实现接口)。此外,我想初始化这个类的一个对象并将其转换为我的特定接口。

我试过了.loadClass()class.forName()如果我Myclass.newInstance转换到我的接口,我会得到一个 ClassCastException。

我如何对我的插件加载器进行编程,以便将我的类加载到我的 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();

现在我得到这个错误-> java.lang.ClassCastException: class com.myapp.mod throw at loadedClass.asSubclass(..); 找到了特定的类,因为如果我将 com.myapp.mod 更改为它抛出 classnotfound execption 的任何内容。我尝试使用 ModInterface ClassLoader,但没有任何改变。with(out) 我会得到同样的错误。

注意:// 我使用 2 个项目。1 用于我的服务器应用程序,另一个用于我应该加载的插件。两者具有相同的接口。

编辑://

使用此代码,我从所需的类中获得了 Object 类型的对象,但它不是我的 ModInterface 的实例,尽管我的类实现了我的 ModInterface。如果我尝试将我的对象转换为我的 ModInterface,则会出现错误。这是我的短代码:

Class c = clazzLoader.loadClass(element.getName().replaceAll(".class", "").replaceAll("/", "."));
Object instance = c.newInstance();
4

3 回答 3

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返回 a Class<?>,之后必须对其进行强制转换。这个演员可以更好地完成Class.asSubClass。如果加载的类没有实现接口,你只会得到一个ClassCastException.

但是...如果您想建立一个简单的插件机制,您应该考虑使用ServiceLoader,这需要您的可插入 JAR 来定义服务配置文件。有关更多说明,请参阅链接。

顺便说一句:要在您的代码示例中加载的类看起来更像是一个包名,因此无法找到它。也许这是你的问题?

于 2013-07-22T13:25:29.863 回答
0

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

谢谢你的帮助

于 2013-07-22T22:41:27.747 回答
0

好吧,您似乎想动态加载interfacesayA以及实现classsay 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

类#cast()

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

反射教程将帮助您了解如何以反射方式创建实例。

于 2013-07-22T12:53:45.830 回答