Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does visibility work for Java nested classes?

I'm trying to learn what visibility to assign to nested classes, besides what my IDE yells at me that I have to do. This can get arbitrarily complicated, so I need to understand the general rules.

public class A {
    private static class B {
        public int foo; // accessible in A?
        private int bar; // accessible in A?
        public static class C { // accessible in A? everywhere?
        }
        private static class D { // accessible in A?
        }
    }
}

As far as I understand, modifiers seem to resolve at the "file" level, not at the level of the encapsulating class. Once one thing is private, anything inside it is private.

What's the actual mechanism of this or the technical explanation? Is this documented somewhere or do I just need to read the JLS?

like image 859
djechlin Avatar asked Feb 01 '15 21:02

djechlin


People also ask

Do Nested classes have to be private?

As a member of the OuterClass , a nested class can be declared private , public , protected , or package private. (Recall that outer classes can only be declared public or package private.)

Can Nested classes access private members in Java?

Nested inner classes have access to the members of the outer class, including the private ones. A nested class can be public, private, package private, or protected as a member of the outer class. The outer java classes can access inner class private or protected members.

What visibility modifier should an inner class have?

We can use all of the standard visibility modifiers on inner classes, so a static inner class could be private, protected, default, or publicly visible.

Can inner classes be public in Java?

Java inner class can be declared private, public, protected, or with default access whereas an outer class can have only public or default access.


2 Answers

One of the best summaries of access visibility that I've seen is in the Java Tutorials > Controlling access to members of a class, but it glosses over some of the key details. The question I think you are asking is answered in § 6.6.1 of the JLS for SE 7: "Determining Accessibility"

If ... public ... Otherwise, if ... protected ... Otherwise, if ... package access ...

Otherwise, the member or constructor is declared private, and 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.

If you read that carefully:

  1. any access
  2. within the body of the top level class
  3. to another private (not package-private - that's different) member
  4. regardless of how deep it is nested
  5. is permitted

So: any member inside any depth of private nested classes is accessible anywhere within the body of the top level class (including within other nested sibling classes). However a private nested class, and any member within, is not visible to other top level classes.

For example:

public class A {
    private static class B {
        public int foo; // accessible in A and P
        private int bar; // accessible in A and P   
        public static void test(){
            P p = new P();
            p.foo = 1; p.bar = 1;
        }
    }
    private static class P {
        public int foo; // accessible in A and B
        private int bar; // accessible in A and B   
        public static void test(){
            B b = new B();
            b.foo = 1; b.bar = 1;
        }
    }
    public static void test(){
        B b = new B();
        b.foo = 1; b.bar = 1;
        P p = new P();
        p.foo = 1; p.bar = 1;       
    }
}

Note: This isn't "file level" though. Declare another top level class in that file (which could not be public - only one of those allowed per file) and it couldn't see those same nested private members.

class X {
    public static void test() {
        // all of these statements fail ...
        A.B b = new A.B();
        b.foo = 1; b.bar = 1; 
        b.test();
        A.P p = new A.P();
        p.foo = 1; p.bar = 1;  
        p.test();
    }

}
like image 191
Andy Brown Avatar answered Oct 03 '22 00:10

Andy Brown


Accessibility is relative to the access source. First

Otherwise, the member or constructor is declared private, and 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.

So all members you've declared in A or nested within class in A are accessible in A.

If you're not within A, then private members of A are not accessible. That means B is not accessible. Since foo, bar, C and D are members of B, you need B to access them. But since B is not accessible, you can't access those either.

public class Unrelated {
   {
       B b; // nope
       A.B b; // nope
       A.B.C c; // nope 
   }
}

These rules are more or less all defined in this section of the JLS.

like image 43
Sotirios Delimanolis Avatar answered Oct 03 '22 01:10

Sotirios Delimanolis