关于Java:为什么EnUM实现不能访问枚举类中的私有字段

Why can enum implementations not access private fields in the enum class

我刚刚回答了这个问题,说了如何解决编译问题:

如何通过重写方法在Java枚举中使用字段?

但我不明白的是为什么错误首先发生。

以下是编写为枚举的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public enum MyEnum {


    FIRST {
        @Override
        public String doIt() {
            return"1:" + someField; //error
        }
    },
    SECOND {
        @Override
        public String doIt() {
            return"2:" + super.someField; //no error
        }
    };

    private String someField;


    public abstract String doIt();

}

这和抽象类完全一样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
abstract class MyClass {
    class FIRST extends MyClass {
        @Override
        public String doIt() {
            return"1:" + someField; //no error
        }
    };
    class SECOND extends MyClass {
        @Override
        public String doIt() {
            return"2:" + super.someField; //no error
        }
    };

    private String someField;

    public abstract String doIt();
}

enum实现中,如果是FIRST,则不能访问someField。但是在抽象类的情况下,它可以。

另外,添加super可以解决问题,删除字段上的private修饰符也可以解决问题。

有人知道为什么这种轻微的行为怪癖会发生吗?


抽象类不等价于枚举,因为枚举是隐式公共静态final。因此,如果您使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
abstract class MyClass {

    static class FIRST extends MyClass {

        @Override
        public String doIt() {
            return"1:" + someField; // error
        }

    };

    static class SECOND extends MyClass {

        @Override
        public String doIt() {
            return"2:" + super.someField; // no error
        }

    };

    private String someField;

    public abstract String doIt();

}

如http://docs.oracle.com/javase/tutorial/java/javaoo/nested.html"静态嵌套类"一章所述:

A static nested class cannot refer directly to instance variables or
methods defined in its enclosing class: it can use them only through
an object reference.

因此,EDOCX1的需求(0)。如果字段是protected,而不是private,也可以使用this


当一个标识符被解析时,Java倾向于在继承成员上使用词法范围。因此,当您有一个扩展外部类的内部类,并且在不使用thissuper的情况下使用外部类的字段时,将访问外部实例的字段,如果内部类是static则访问失败,因为此时没有外部实例。相反,当使用super时,您显式地访问继承的成员。注意,enum类是隐含的static类。您甚至可以使用this访问继承成员,但如果声明为private则必须使用((MyClass)this).someField访问它。


我不同意接受的回答。

枚举常量声明是隐式的public static final,但不是枚举常量所属的类。

摘自JSL第8章类

The optional class body of an enum constant implicitly defines an anonymous class declaration (§15.9.5) that extends the immediately enclosing enum type. The class body is governed by the usual rules of anonymous classes.

"Anonmous类的规则"是什么?

从JSL第15章:

An anonymous class declaration is automatically derived from a class instance creation expression by the Java compiler.

An anonymous class is never abstract (§8.1.1.1).

An anonymous class is always implicitly final (§8.1.1.2).

An anonymous class is always an inner class (§8.1.3); it is never static (§8.1.1, §8.5.1).

如果枚举等价类是静态类,如何解释下面的错误?

1
2
3
4
5
public enum MyClass {
    First {
        public static int b;  //(2)Illegal static declaration in inner class
    };
}

但是为什么一个内部阶级不能进入外部阶级的领域呢?

可能的枚举等效类可能如下所示,这会产生与枚举类相同的错误:

1
2
3
4
5
6
7
8
9
10
11
abstract class MyClass {    
    private int someField;
    static {
        class First extends MyClass {
            public void method() {
                System.out.println(someField);
            }
            private static int b;
        }
    }
}

更多:

  • 嵌套枚举是静态的?
  • 枚举是如何实现的?

FIRST类是MyClass的一个内类,也是一个子类。访问其中的someField时没有看到错误的原因是您访问的是外部类的someField而不是超级类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class MyClass {
    class FIRST extends MyClass {
        @Override
        public String doIt() {
            super.someField ="super";
            return"1:" + someField;
        }
    };

    private String someField ="outer";

    public String doIt(){return"";}

    public static void main(String[] args) {
        System.out.println(new MyClass().new FIRST().doIt());
    }
}

打印1: outer

在另一种情况下,枚举常量表现为静态嵌套的子类,而不是内部类,因此它们没有对外部类的引用,只有它们的超级类。