Java Applet - 无法继承 final class

Java Applet - Cannot inherit from final class

我们有一个 java 小程序,它在大多数客户端环境中工作正常,主要是 Windows 7,但最近我们被要求也支持 Ubuntu 客户端。

问题是当小程序在 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.access0(URLClassLoader.java:71)
    at java.net.URLClassLoader.run(URLClassLoader.java:361)
    at java.net.URLClassLoader.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.access01(JNLPClassLoader.java:103)
    at net.sourceforge.jnlp.runtime.JNLPClassLoader.run(JNLPClassLoader.java:1636)
    at net.sourceforge.jnlp.runtime.JNLPClassLoader.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 版本)。

我理解异常的含义 - 并且快速 google 搜索发现多个 SO 问题,主要归结为构建路径与 class 不同的建议路径,这样在编译时基 class 不是最终的,但在运行时 classloader 发现它是最终的。

但是,我不明白怎么会这样:

我假设 class 它在调用 loadClass 之前立即抱怨 NlxBrowserJsEngine,运行 - 对吗?这个 class 的基数 class 是它认为最终的那个吗?

为了完整性 - 这里是 class 的声明(这是异常抱怨的第 46 行)和它仅有的两个字段的声明:

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

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

这里是基础的声明class:

public abstract class NlxJsEngine {

感谢您的任何见解!

我终于找到了原因。

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

class NlxBrowserJsEngine 的一个方法调用了另一个 class 的静态方法 - 这个 class 扩展自 netscape.javascript.JSObject.

oracle implementation 中,此 JSObject class 未声明为最终的,因此扩展它可以正常工作。

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

我不确定这种不兼容性是代表 IcedTea 实施者的疏忽,还是故意造成的(也许是出于安全考虑?)。无论哪种方式都给我们带来了很大的问题。

通过大量重构本来可以克服这个问题,但在我们的案例中,这被认为是不值得的,因此我们决定要求我们的用户安装 Oracle JVM。