Java Applet - 无法从最终类继承

时间:2015-02-27 07:50:25

标签: java applet classloader final

我们有一个java applet在大多数客户端环境中运行正常,主要是Windows 7,但最近我们也被要求支持Ubuntu客户端。

问题是当applet在Ubuntu客户端上运行时(运行Firefox和本机安装的“IcedTEA”Java VM 1.7.0_75),我们得到了这个例外:

java.lang.VerifyError: Cannot inherit from final class
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at net.sourceforge.jnlp.runtime.JNLPClassLoader.access$1701(JNLPClassLoader.java:103)
    at net.sourceforge.jnlp.runtime.JNLPClassLoader$5.run(JNLPClassLoader.java:1636)
    at net.sourceforge.jnlp.runtime.JNLPClassLoader$5.run(JNLPClassLoader.java:1634)
    at java.security.AccessController.doPrivileged(Native Method)
    at net.sourceforge.jnlp.runtime.JNLPClassLoader.findClass(JNLPClassLoader.java:1633)
    at net.sourceforge.jnlp.runtime.JNLPClassLoader.loadClassExt(JNLPClassLoader.java:1670)
    at net.sourceforge.jnlp.runtime.JNLPClassLoader.loadClass(JNLPClassLoader.java:1471)
    at com.renosci.Nlx.chartapplet.NlxBrowserJsEngine.<init>(NlxBrowserJsEngine.java:46)
    at com.renosci.Nlx.chartapplet.UtilityApplet.init(UtilityApplet.java:87)
    at sun.applet.AppletPanel.run(AppletPanel.java:436)
    at java.lang.Thread.run(Thread.java:745)

我们不会在Windows下获得此异常(诚然,不同的JVM版本和Windows上我们正在使用的 Oracle提供的是VM而不是这个IcedTea版本。)

我理解异常的含义 - 并且快速谷歌搜索显示多个SO问题,主要归结为构建路径与类路径不同的建议,这样在编译时基类不是最终的,但在运行时,类加载器正在寻找最终版本。

但是,我不明白这是怎么回事:

  • 抛出错误的类是从作为代码库一部分的抽象基类扩展而来的, 并且根据我们的版本控制系统从未是最终的

  • 我正在测试的目标机器上不存在此类的任何其他版本 - 实际上我为此测试创建了一个新的VM并立即解决了问题

    < / LI>

我假设它正在抱怨NlxBrowserJsEngine的类,在调用loadClass之前立即运行 - 是正确的吗?而且这个类的基类是它认为是最终的类?

为了完整性 - 这是类的声明(这是异常所抱怨的第46行)以及它所拥有的仅有两个字段的声明:

public class NlxBrowserJsEngine extends NlxJsEngine {  /* Line 46 */
    private JSObject windowObj;
    static private Object evalLock = new Object();

JSObject是netscape.javascript.JSObject,由Java浏览器插件提供。

以下是基类的声明:

public abstract class NlxJsEngine {

感谢您的任何见解!

1 个答案:

答案 0 :(得分:0)

我最终追查了原因。

如@ immibis的评论所示,异常是在类初始化期间,而不是在构造实例期间。

NlxBrowserJsEngine类的一个方法调用另一个类的静态方法 - 该类从netscape.javascript.JSObject扩展。

oracle implementation中,这个JSObject类没有被声明为final,所以扩展它可以正常工作。

IcedTea实现中,JSObject是最终的。因此,在IcedTea JVM插件中加载此类时,会抛出异常。

我不确定这种不兼容性是代表IcedTea实现者的疏忽,还是故意做(可能是出于安全性?)。无论哪种方式,它都给我们带来了很大的问题。

通过广泛的重构,可以克服这个问题,但在我们的案例中,这不值得考虑,因此我们决定要求我们的用户安装Oracle JVM。