8
votes

Update:

I'm still a unclear about this. I'm trying to find the JLS to describe this behaviour. Instead, I found this quote in 8.3 of the JLS:

Member class declarations (§8.5) describe nested classes that are members of the surrounding class. Member classes may be static, in which case they have no access to the instance variables of the surrounding class; or they may be inner classes (§8.1.3).

Doesn't this mean the nested static class should not have access to the outer class variables? Where can I find clarification of what the behaviour should be?

End Update

I am seeking some clarification of the accesiblity of the private members of an outer class by an instance of a static nested class. The Java tutorials state:

a static nested class is behaviorally a top-level class that has been nested in another top-level class for packaging convenience

The accepted answer from this question (Java inner class and static nested class) mentions:

The only real conceivable reason to create a static inner class is that such a class has access to its containing class's private static members

But it seems a static nested class also has access to the private members of any instance of the enclosing class? This would be behaviourly different from any other top level class. In the example below, the static nested class Builder can access the private members of any instance of the Config class. But another top level class would not be able to do this (e.g. an instance of ConfigTest would not be able to change the private members of a config object as shown in the commented manipulateConfig method.

Am I understanding this correctly? I haven't found a reference in the JLS to clarify this for me.

Config:

public class Config {

    private String param1;
    private int param2;

    private Config() {}

    public String getParam1() { return param1; }
    public int getParam2() { return param2; }

    @Override
    public String toString() {
        return "Config{" + "param1=" + param1 + ", param2=" + param2 + '}';
    }



    public static class Builder {

        private String param1;
        private int param2;

        public Builder setParam1(String param1) { this.param1 = param1; return this; }
        public Builder setParam2(int param2) { this.param2 = param2; return this; }

        public Config build() {
            Config config = new Config();
            config.param1 = param1;  // <- Accessing private member of outer class
            config.param2 = param2;
            return config;
        }


        public void modifyParm2(Config config, int newVal) {
            config.param2 = newVal;  // <- Able to modify private member of any enclosing class
        }

    }

}

ConfigTest:

public class ConfigTest {


    private Config getConfig() {

        Config.Builder builder = new Config.Builder();

        Config config = builder
                .setParam1("Val1")
                .setParam2(2)
                .build();

        return config;

    }

//    private void manipulateConfig(Config config, String newParam1) {
//        config.param1 = newParam1;
//    }

    public static void main(String[] args) {

        ConfigTest configTest = new ConfigTest();
        Config config = configTest.getConfig();
        System.out.println(config);

        Config.Builder anotherBuilder = new Config.Builder();
        anotherBuilder.modifyParm2(config, 3);
        System.out.println(config);

//        configTest.manipulateConfig(config, "val11");

    }

}

Output of running ConfigTest:

Config{param1=Val1, param2=2}
Config{param1=Val1, param2=3}
1
If the compiler lets you do it...William Price
'static inner' is a contradiction in terms. You mean 'static nested'.user207421
@EJP Thanks for the correction. I changed remaining terminology mis-use that I could find.Glenn

1 Answers

11
votes

The answer to which you link is not entirely correct: nested static classes have access to all members of its enclosing class, including private members.

They do not get access to instance members, public or private, of its enclosing instance. However, if you pass a method of a static nested class an instance of the enclosing class, the nested class would be able to access all members of the enclosing class, regardless of their access level.

I think the static/non-static confusion comes from this line of JLS:

Member classes may be static, in which case they have no access to the instance variables of the surrounding class

This does not mean that static nested classes have no access to instance variables at all. It means that static nested classes have no access to instance variables of the enclosing class "for free", the way the non-static nested classes do.

To me, the two main differences between a static nested class and a top-level class are

  1. Nested static classes and interfaces express a closer association with their enclosing classes / interfaces. For example, Map.Entry nested interface is a better choice than MapEntry top-level interface for readability.
  2. Nested classes can serve as an implementation detail of another class, if you declare them private. You cannot do that with top-level classes, because they would remain accessible at least to the classes in the same package.