为什么枚举类型上的私有字段对包含类可见?

10
public class Parent {

    public enum ChildType {

        FIRST_CHILD("I am the first."),
        SECOND_CHILD("I am the second.");

        private String myChildStatement;

        ChildType(String myChildStatement) {
            this.myChildStatement = myChildStatement;
        }

        public String getMyChildStatement() {
            return this.myChildStatement;
        }
    }

    public static void main(String[] args) {

        // Why does this work?
        System.out.println(Parent.ChildType.FIRST_CHILD.myChildStatement);
    }
}

在这个枚举中,关于父类子类、同一包中的类等访问控制是否有其他规则?我在规范中该在哪里找到这些规则?

3个回答

21

这与它是枚举类型无关,而与包含类型对嵌套类型的私有访问有关。

根据Java语言规范,第6.6.1节:

否则,如果成员或构造函数被声明为private,则仅当它出现在包含成员或构造函数声明的顶级类(§7.6)的主体内部时,才允许访问。

例如,这也是有效的:

public class Test {

    public static void main(String[] args) {
        Nested nested = new Nested();
        System.out.println(nested.x);
    }

    private static class Nested {
        private int x;
    }
}

有趣的是,C# 的工作方式略有不同 - 在 C# 中,私有成员仅在类型的程序文本中可访问,包括从任何嵌套类型中。因此,上面的 Java 代码将无法工作,但这段代码可以:
// C#, not Java!
public class Test
{
    private int x;

    public class Nested
    {
        public Nested(Test t)
        {
            // Access to outer private variable from nested type
            Console.WriteLine(t.x); 
        }
    }
}

...但如果你只是将Console.WriteLine更改为System.out.println,这在Java中是可以编译的。因此,相比于C#,Java对私有成员要求稍微宽松一些。


谢谢Jon。我一直听说枚举被称为“特殊类类型实例”,或类似的术语,这也是为什么类和枚举适用许多相同规则的原因,而规范没有提供任何额外注释的原因。 - user4903
@irreputable:有趣……Java版本在C#中无法工作。我猜嵌套的主体仍然算作“顶层类的主体”。将修改答案以使其更清晰。 - Jon Skeet

7
因为enum实际上是父类的内部类。

1
@T.J. Crowder - 这有点复杂;教程描述了从嵌套类访问_enclosing_类的字段。OP的示例则相反。这方面的规则在Java语言规范的第6.6节中有说明。还可以参见此线程 - Ted Hopp

1

一个最高级别的类就像一个村庄,每个人都认识每个人,没有秘密。其中的嵌套单元并不改变这个事实。

class A
    private a;

    class B
        private b

        a = x; // ok

    new B().b = y; // ok

    class C extends A{}

    new C().a = z; // ok

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接