【问题标题】:Load Class, Generate Object of this class加载类,生成该类的对象
【发布时间】:2013-07-21 04:57:12
【问题描述】:

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

【问题讨论】:

  • 愿意发布您尝试过的代码吗?另外,你有使用反射的理由吗?让编译器确保代码的类型安全通常是首选,除非您有一些必须推迟到运行时。
  • 我有点失败,我想从 Jar 文件加载一个类,这个类实现了一个接口。生成的对象应该被转换为这个已知的接口,所以我可以在我的插件加载器中正常使用它。不,我在发布代码时没有问题,但我无法在 8 小时内回答我的主题,因为它出现在规则中。
  • 您无需回答您的主题。只需编辑您的问题并发布代码。
  • 代码已添加,希望你能帮助我:)
  • 标题中无需添加major标签。

标签: java class dynamic reflection classcastexception


【解决方案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(":-)");
    }
}

那么下面的代码 sn-p 会做你想做的事(并打印出“:-)”):

Class<?> loadedClass = Class.forName("test.impl.PluginImpl");
Class<? extends Plugin> pluginClass = loadedClass.asSubclass(Plugin.class);
Plugin plugin = pluginClass.newInstance();
plugin.service();

您还可以使用适当的类加载器获取正确的类引用(就像您在代码示例中所做的那样)。

注意,Class.forName 返回一个 Class&lt;?&gt;,必须在之后进行转换。使用Class.asSubClass 可以更好地完成此演员阵容。如果加载的类没有实现接口,你只会得到一个ClassCastException

然而...如果你想建立一个简单的插件机制,你应该考虑使用ServiceLoader,这需要你的可插入JARs来定义一个服务配置文件。有关详细说明,请参阅链接。

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

【讨论】:

  • 这也可能是我的问题。我用我的 jar 的绝对路径获得了文件句柄,我定义在每个插件中它必须是一个名为 com.myapp.mod 的路径。 Mod 是实现我的接口并被我的服务器识别的类。现在我尝试通过我的文件句柄加载类,我知道我要加载的类称为 com.myapp.mod。
  • 我的路径是正确的,我的班级被找到,但如果我尝试使用 .asSubClass(..) 我得到一个错误。见上文。
【解决方案2】:

看来你想动态加载 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 将帮助您了解如何以反射方式创建实例。

【讨论】:

  • 我将它添加到上面的 cmets 中,我实际上有一个接口,我的所有插件都必须实现。我的服务器也有这个接口,我只想加载一个类并将其转换为我的接口。
【解决方案3】:

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

感谢您的帮助

【讨论】:

    猜你喜欢
    • 2018-07-29
    • 1970-01-01
    • 1970-01-01
    • 2012-09-19
    • 2012-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    相关资源
    最近更新 更多