Search code examples
javaencapsulationstatic-membersnested-class

Why is it possible to access members of a nested static class?


I have a nested static class named Adjudicator (don't ask ... I had named it a bit whimsically before I had read about the Builder Pattern in Effective Java) which is a builder, i.e. Client.Adjudicator builds Client objects.

Like the builder that Joshua Bloch gives as an example in Effective Java, it builds objects of the "enclosing" class (static nested classes are not truly enclosed) by invoking the enclosing class's constructor. My class looks like this:

public class Client extends DB {

    private IntegerProperty id =         new SimpleIntegerProperty();
    private LongProperty    defmrnKey =  new SimpleLongProperty();
    private StringProperty  lastName =   new SimpleStringProperty();
    private StringProperty  midName =    new SimpleStringProperty();
    private StringProperty  firstName =  new SimpleStringProperty();
    private IntegerProperty doB =        new SimpleIntegerProperty();
    private StringProperty  gender =     new SimpleStringProperty();

    :
    :

    Client(Client cli) {  // Copy constructor

        this.id.set(cli.getID());
        this.defmrnKey.set(cli.getDefMRNKey());
        this.lastName.set(cli.getLastName());
        this.midName.set(cli.getMidName());
        this.firstName.set(cli.getFirstName());
        this.doB.set(cli.getDoB()); 
        this.gender.set(cli.getGender());
    }

    Client(Client.Adjudicator ad) {  // Invoked by builder

        this.id.set(ad.m_id);
        this.defmrnKey.set(ad.m_defmrnkey);
        this.lastName.set(ad.m_ln);
        this.midName.set(ad.m_mn);
        this.firstName.set(ad.m_fn);
        this.doB.set(ad.m_dob); 
        this.gender.set(ad.m_gen);
    }

    :
    :

    public static class Adjudicator {


        private int     m_id               = DB.KEY_UNDEFINED;
        private long    m_defmrnkey        = DB.KEY_UNDEFINED;
        private String  m_ln               = null;
        private String  m_mn               = null;
        private String  m_fn               = null;
        private int     m_dob              = DB.KEY_UNDEFINED;
        private String  m_gen              = null;

        :
        :

        public Client build() {

            // Invariants all checked here; if ok then...

            return new Client(this);
        }
    }
}

The static nested class is, from the point of view of the JVM, a top-level class and so instances of it don't depend on any instance of Client.

And yet, my Client class is able to freely access the private members of its builder class ... even though they're private and in a separate top-level class.

Why does this work? Doesn't this break encapsulation? I'm happy that this works, but this is not intuitive to me.


Solution

  • The static nested class is, from the point of view of the JVM, a top-level class

    Not exactly as you've found out. The scope of a private member is the top-level enclosing class. In your case, it is the whole Client class.

    Note that it works both ways and your Adjudicator class can access the private members of your Client class too.

    Reference: JLS #6.6.1

    if the member is declared private, then access is permitted if and only if it occurs within the body of the top level class that encloses the declaration of the member