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

Are there any additional rules with regard to access control for Parent subclasses, classes within the same package, etc., in reference to this enum? Where might I find those rules in the spec?

3 Answers3

21

It has nothing to do with it being an enum - it has everything to do with private access from a containing type to a nested type.

From the Java language specification, section 6.6.1:

Otherwise, if the member or constructor is declared private, then access is permitted if and only if it occurs within the body of the top level class (ยง7.6) that encloses the declaration of the member or constructor.

For example, this is also valid:

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

Interestingly, C# works in a slightly different way - in C# a private member is only accessible within the program text of the type, including from any nested types. So the above Java code wouldn't work, but this would:

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

... but if you just change Console.WriteLine to System.out.println, this does compile in Java. So Java is basically a bit more lax with private members than C# is.

Pang
  • 9,564
  • 146
  • 81
  • 122
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thanks Jon. I've always heard enums called "special class type instances", or a similar term, which I guess is the reason why a lot of the same rules apply for a class and an enum, and the specification doesn't provide any additional notes. โ€“  Feb 21 '11 at 18:05
  • @irreputable: Interesting... the Java version wouldn't work in C#. I guess the body of Nested still counts as the "body of the top-level class". Will amend the answer to make it clearer. โ€“ Jon Skeet Feb 21 '11 at 21:13
7

Because the enum is effectively an inner class of the parent.

pauljwilliams
  • 19,079
  • 3
  • 51
  • 79
  • 1
    @T.J. Crowder - It's slightly more complicated; the tutorial describes accessing fields of the _enclosing_ class from the _nested_ class. The example by OP is the other way around. The rules for that are in [section 6.6](http://java.sun.com/docs/books/jls/third_edition/html/names.html#6.6) of the Java language specification. Also see [this thread](http://stackoverflow.com/questions/2221607/in-java-nested-classes-can-the-enclosing-class-access-private-members-of-inner-c). โ€“ Ted Hopp Feb 21 '11 at 18:23
1

A top level class is like a village, everybody knows everybody, there are no secrets. Nested units within it don't change that fact.

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
irreputable
  • 44,725
  • 9
  • 65
  • 93