【问题标题】:Cannot make a static reference to the non-static field memberVariable with private variable无法使用私有变量对非静态字段 memberVariable 进行静态引用
【发布时间】:2011-12-09 08:28:37
【问题描述】:

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

}

【问题讨论】:

    标签: java enums


    【解决方案1】:

    错误信息令人困惑。

    问题是当你给一个枚举值代码时,你正在创建一个枚举的匿名子类。 (它的类将是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;
    }
    

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

    【讨论】:

    • 听起来很合理。谢谢你的答案和“超级”的提示!
    • 我已将其记录为 javac 错误。
    • 他们说它应该在几天内可见。 bugs.sun.com/bugdatabase/view_bug.do?bug_id=7119746 我注意到 Oracle 接受我的错误 比 Sun 快得多
    • 这不是错误。 Java Puzzlers 中某处提到了它。编译器错误通常不是。 / 一个子类可以访问它的超类的成员变量,如果超类是(或在其中)同一个外部类。
    • 对于您当前的最后一段代码,NestedNotEnum 实例有两个可用的memberVariable 实例。可能令人惊讶(以及为什么该错误很有用)是两个 get 方法返回两个不同实例中的变量值。
    【解决方案2】:

    Josh Bloch 和 Neal Gafter 在Java Puzzlers 中的 Puzzle 92(Twisted Pair)中涵盖了类似的问题。

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

    扩展外部类的内部类可以通过this 或其他实例访问外部类的私有实例字段。

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

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

    或者

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

    【讨论】:

      【解决方案3】:

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

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-11-04
        • 1970-01-01
        • 2015-11-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多