Java 如何使用由不同类加载器实例化的对象

Java 如何使用由不同类加载器实例化的对象,java,jar,applet,classloader,classcastexception,Java,Jar,Applet,Classloader,Classcastexception,我的小程序需要属于外部JAR(签名JAR)和本机库的类。我在applet.jar中部署这些jar。要从这些JAR加载类,我发现类很有用。我首先构建了一个控制台应用程序来测试applet的功能,JarClassLoader对我来说运行良好。 接下来,我用另外两个公共方法编写了MyApplet类,比如action1()和action2()。正如JarClassLoader所描述的,我编写了一个MyAppletLauncher类。(见下面的代码)。为了获得对JarClassLoader实例化的MyAp

我的小程序需要属于外部JAR(签名JAR)和本机库的类。我在applet.jar中部署这些jar。要从这些JAR加载类,我发现类很有用。我首先构建了一个控制台应用程序来测试applet的功能,JarClassLoader对我来说运行良好。 接下来,我用另外两个公共方法编写了MyApplet类,比如action1()和action2()。正如JarClassLoader所描述的,我编写了一个MyAppletLauncher类。(见下面的代码)。为了获得对JarClassLoader实例化的MyApplet对象的引用,我向JarClassLoader类添加了getApplet()方法

MyApplet.java:

public class MyApplet extends Applet {
    public void init()    { ... }
    public void start()   { ... }
    public void stop()    { ... }
    public void destroy() { ... }

    public String action1() {
        ...
    }
    public int action2() {
        ...
    }
}
MyAppletLauncher.java:

public class MyAppletLauncher extends Applet {
    private JarClassLoader jcl;
    public void init() {
        jcl = new JarClassLoader();
        jcl.initApple("MyApplet", this);
    }
    public void start() {
        jcl.startApplet();
    }
    public void stop() {
        jcl.stopApplet();
    }
    public void destroy() {
        jcl.destroyApplet();
    }
    public String action1() {
        return ((MyApplet) jcl.getApplet()).action1(); // <-- ClassCastException
    }
    public int action2() {
        return ((MyApplet) jcl.getApplet()).action2(); // <-- ClassCastException
    }
}
公共类MyAppletLauncher扩展了小程序{
私有JarClassLoader jcl;
公共void init(){
jcl=new-JarClassLoader();
jcl.initApple(“MyApplet”,this);
}
公开作废开始(){
jcl.startApplet();
}
公共停车场(){
jcl.stoppapplet();
}
公共空间销毁(){
jcl.destroyApplet();
}
公共字符串action1(){

return((MyApplet)jcl.getApplet()).action1();//我认为您忽略了启动器applet的要点。它一方面充当applet容器和系统类加载器之间的垫片,另一方面充当jcl加载的真实applet和jcl之间的垫片。除了applet生命周期方法之外,启动器applet中不应该有任何内容

我不确定除生命周期方法之外的任何方法如何在启动程序小程序上被调用。这不会是偶然的,所以请停止尝试。在真正的小程序类和您需要的任何帮助程序类中实现小程序的所有功能,就好像启动程序小程序不存在一样


如果您必须让外部组件查找小程序并调用其上的方法,那么请修改JCL或将其子类化以提供附加的垫片方法,使用它已经用于应用程序生命周期方法的相同模型。

我们看不到代码的这一部分,但是如果您的
JarClassLoader
链接到父类加载器c如果接口是由主类加载器加载的,而不是从定制的外部JAR加载的,那么接口解决方案应该可以正常工作

您需要做的是这样的事情:

public void init() {
    jcl = new JarClassLoader(this.getClass().getClassLoader());
    jcl.initApplet("MyApplet", this);
}
JarClassLoader
应该调用。这样,“主”类加载器可以加载的任何类将只加载一次,因此转换到接口应该可以工作

更新:如果无法绕过
JarClassLoader
s的非委托行为,那么下一个最好的选择就是反射。反射虽然不好,但至少是有效的

public void action1() {
    Applet applet = jcl.getApplet();
    Method action = applet.getClass().getDeclaredMethod( "action1" );
    action.invoke( applet );
}

也许小程序需要接受来自Javascript的调用?没错,biziclop,我直接从Javascript调用action1()和action2()。Javascript调用小程序的方法通常非常混乱,但是的,我想这可能是正在发生的事情。我猜其他小程序也可能会这样做(也很混乱)。编辑以添加建议,用于向外部组件公开接口。我不确定使用其他垫片方法是什么意思。您是否建议我将action1()和action2()添加到(JCL的子类)JCL,然后让JCL调用start()/stop()在这些方法中?这里的要点是,我需要将网页中的数据输入小程序,并将结果(可能是大量数据)返回网页。我可以在开始()之前设置参数(就像我在网页中使用的一样)但我无法从中获取数据,是吗?不幸的是,
JarClassLoader
似乎没有正确地委托给其父级
ClassLoader
(默认情况下为
ClassLoader.getSystemClassLoader()
)因为文档中的限制包括它可能从系统内置库以外的位置加载系统类。讨厌。但是,可以想象接口解决方案无论如何都可以工作。在这种情况下,反射。我在上面的源代码中添加了JCL构造函数;)。我将尝试在您建议时传递父类加载程序我按照你的建议调用了JCL构造函数,但仍然出现了令人讨厌的强制转换异常。即使在实例化JCL
this.getClass().getClassLoader().loadClass(“MyInterface”);
之前显式加载接口类,我也会得到异常。
public void action1() {
    Applet applet = jcl.getApplet();
    Method action = applet.getClass().getDeclaredMethod( "action1" );
    action.invoke( applet );
}