为什么我不能在匿名内部类中访问重写的公共字段?

时间:2012-08-18 23:31:55

标签: java inner-classes scriptengine

我有一个课程,我无法改变如下:

public class Foo {
    public final int ID=0;
    public int bar;
    public final Object baz=null;
}

我想要一个覆盖Foo的匿名内部类,例如:

public Foo newFoo(final int mID, final int mbar, final Object mbaz) {
    return new Foo(){
        public final int ID = mID;
        public int bar = mbar;
        public final Object baz = mbaz;
    };
}

然后我有一个javax.script.ScriptEngine我希望在JS中调用类似的东西:newFoo(0,0,undefined)["ID"]

我的问题是我得到了这样的例外:

sun.org.mozilla.javascript.internal.WrappedException: Wrapped java.lang.IllegalAccessException: Class sun.org.mozilla.javascript.internal.JavaMembers can not access a member of class Baz$1 with modifiers "public final" (mod.js#9) in test.js at line number 9

我不明白我是如何在这里遇到问题的:如果newFoo返回普通的'Foo,但是如果我尝试覆盖Foo一个匿名的内部类,即使它们是公开的,我也无法访问任何被覆盖的成员。

2 个答案:

答案 0 :(得分:2)

我认为这个问题有两个方面。

您的Java代码在语法上是有效的(我认为),但它几乎肯定不会按照您的意愿执行。具体来说,匿名类中的声明不会替换Foo类中的声明。相反,匿名类的每个实例都有两组字段。 Foo中声明的方法只能看到原始字段,匿名类中声明的任何方法都会看到新字段。

如果要为匿名子类中的字段设置不同的值,则:

  • 他们不能是最终的,
  • 他们需要被指派不再重新申报。

我无法真正建议解决此问题的最佳方法,但我认为您需要启动,方法是将Foo字段设为私有,并为其提供getter和/或setter他们。对于setter,您可以使用访问修饰符来允许匿名子类设置字段,但不能设置不相关的代码。

最重要的是,您 覆盖字段中的Java。你的代码所做的不是重写,而是隐藏字段。


另一方面是包装异常来自Javascript引擎。我认为问题是匿名类是隐式私有的,因此您的Javascript代码段试图访问私有类的字段。当Javascript引擎尝试这样做时(我希望使用Java反射),它会获得运行时异常。

唯一不幸的是,异常消息并没有说为什么它无法访问该成员,但是你的Java代码足够“奇怪”,这并不让我感到惊讶。

作为解决方法,我建议用非嵌套类替换匿名类。

答案 1 :(得分:-2)

你没有这样的课程:

public class Foo {
    public final int ID=0;
    public int bar;
    public final Object baz;
}

因为那不会编译(baz不能声明)。