我用一个私有成员变量创建了一个枚举。 当我尝试访问成员变量时,编译状态'无法对非静态字段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);
}
答案 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;
}
};