无法使用私有变量对非静态字段memberVariable进行静态引用

时间:2011-12-09 08:28:38

标签: java enums

我用一个私有成员变量创建了一个枚举。 当我尝试访问成员变量时,编译状态'无法对非静态字段memberVariable进行静态引用'。

如果变量不是私有的(例如受保护或受包保护),则编译正常。我不明白变量的范围与实现的抽象函数的类型(静态,非静态)有什么关系。

有人可以启发我吗?

public enum EnumWithAbstractMethodAndMembers {
    TheOneAndOnly(1) {
        @Override
        public int addValue(final int value) {
            return memberVariable + value;
        }
    };

    private final int memberVariable;

    private EnumWithAbstractMethodAndMembers(final int memberVariable) {
        this.memberVariable = memberVariable;
    }

    abstract int addValue(int value);

}

3 个答案:

答案 0 :(得分:19)

错误消息令人困惑。

问题在于,当您提供枚举值代码时,您正在创建枚举的匿名子类。 (它的类将是EnumWithAbstractMethodAndMembers$1)子类不能访问其超类的私有成员,但是嵌套类可以通过生成的访问器方法。您应该能够访问私有字段,并且它给您的错误消息似乎是错误的。

BTW你可以使用它,但你不需要恕我直言。

    public int addValue(final int value) {
        return super.memberVariable + value;
    }

这是一个较短的示例,我将在错误消息中记录为错误,因为它不会导致问题的解决方案。

public enum MyEnum {
    One {
        public int getMemberVariableFailes() {
            // error: non-static variable memberVariable cannot be referenced from a static context
            return memberVariable;
        }

        public int getMemberVariable2OK() {
            return memberVariable2;
        }

        public int getMemberVariableOK() {
            return super.memberVariable;
        }
    };

    private final int memberVariable = 1;
    final int memberVariable2 = 1;
}

根据Tom Hawkin的反馈,此示例会收到相同的错误消息。

public class MyNotEnum {
    // this is the static context in which the anonymous is created
    public static final MyNotEnum One = new MyNotEnum() {
        public int getMemberVariableFailes() {
            // error: non-static variable memberVariable cannot be referenced from a static context
            return memberVariable;
        }

        public int getMemberVariableOK() {
            return super.memberVariable;
        }
    };
    private final int memberVariable = 1;
}

进行比较

public class MyNotEnum {
    public class NestedNotEnum extends MyNotEnum {
        public int getMemberVariableFailes() {
            // compiles just fine.
            return memberVariable;
        }

        public int getMemberVariableOK() {
            return super.memberVariable;
        }
    }
    private final int memberVariable = 1;
}

答案 1 :(得分:3)

Josh Bloch和Neal Gafter在Java Puzzlers中也提到过类似的问题(我不知道我的副本在哪里,所以我不能给你一个确切的参考)。

枚举没什么特别之处。静态上下文中的任何匿名(或本地)内部类都可以。规则是在超类之前考虑外部类。这对于非静态上下文中的这些类非常有意义。如果将上下文更改为静态更改了哪个变量被查找,则可能会在运行时引入“混淆”(C ++对此类规则更具攻击性)。

扩展外部类的内部类可以访问外部类的私有实例字段,无论是通过this还是其他实例。

由于我们被允许访问,我们需要以某种方式指定我们想要通过内部而不是外部这个。正如Peter Lawrey指出super.member会做的那样。您也可以选择内部,然后使用该表达式:

        return ((EnumWithAbstractMethodAndMembers)this).memberVariable + value;

或者

        EnumWithAbstractMethodAndMembers innerThis = this;
        return innerThis.memberVariable + value;

答案 2 :(得分:0)

错误的主要原因是:您正在尝试从内部实现类引用超类的私有变量(memberVariable)。

要制作无错误代码,您可以执行以下任一操作:

  • 您必须使用super.memberVariable,因为memberVariable 非本地TheOnlyAndOnly()
  • 您可以int memberVariable 公开
  • 你可以这样做:

    TheOneAndOnly(1) {
        int memberVariable=4;
        @Override
        public int addValue(final int value) {
            return memberVariable + value;
        }
    };