2011-12-09 35 views
16

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

} 

回答

19

该错误消息令人困惑。

问题是,当你给一个枚举值代码时,你正在创建一个枚举的匿名子类。 (其类将为EnumWithAbstractMethodAndMembers$1)子类不能访问其超类的私有成员,但嵌套类可以通过生成的访问器方法。你应该能够访问私人领域,它给你的错误信息似乎是不正确的。

顺便说一句你可以使用这个,但你不应该需要恕我直言。

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; 
} 

基于汤姆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; 
} 
+0

Sound的合理性。 Thx的答案和'超级'的提示! – Andreas

+0

我将它记录为'javac'的错误。 –

+1

他们说它应该在几天内可见。 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7119746我注意到Oracle接受我的错误**比Sun快得多。 –

0

误差的主要原因是:你试图要参考从内部实现类的超类的私有变量(memberVariable)。

为了使无差错的代码,你可以做以下之一:

  • 你必须使用super.memberVariable因为memberVariable不是本地TheOnlyAndOnly()
  • 可以使int memberVariable公共
  • 你可以这样做:

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

类似的问题在Java的谜题由乔希布洛赫和Neal Gafter覆盖(我不知道在哪里无论我的副本是,所以我不能给你一个确切的参考)。

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

其延伸的外类可以访问外部类的私有实例字段,无论是通过this或一些其它实例的内部类。

当我们被允许访问,我们需要以某种方式指定我们想通过内这个,而不是外此。正如彼得劳里指出super.member会做。您也可以选择内这一点,然后使用该表达式:

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

或者

 EnumWithAbstractMethodAndMembers innerThis = this; 
     return innerThis.memberVariable + value; 
相关问题