9

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}
Community
  • 1
  • 1
Glenn
  • 8,932
  • 2
  • 41
  • 54

1 Answers1

12

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.
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • With a non-static nested class, access to the private members of the enclosing instance would make sense to me. But with a static nested class, there is no enclosing instance, so it looks like a nested class can access the private members of -any- other instance of the outer class as in the example line `anotherBuilder.modifyParm2(config, 3);` above. That somehow doesn't feel right to me. – Glenn Nov 28 '14 at 03:22
  • @Glenn Why? This makes perfect sense to me: if the two classes are strongly related functionally, but there is no one-to-one relationship among their instances, static classes with access to private members of the enclosing class provide a good choice. – Sergey Kalinichenko Nov 28 '14 at 03:29
  • I guess you are right. It was just a subtlety I didn't realize before and I couldn't find any docs or comments pointing this out. I would then consider the Java Tutorial comment of `a static nested class is behaviorally a top-level class that has been nested in another top-level class for packaging convenience` to be misleading: the tight coupling introduces a behavioural change. In my example, where I wish to use a Builder to generate un-modifiable instances, it happens to be a very useful property. – Glenn Nov 28 '14 at 03:38
  • @Glenn I agree - I think that the tutorial took simplification of the material a little too far. To their defense, use cases for situations when static class should access private instance variables of their enclosing class are hard to explain in the context of a tutorial that introduces its readers to the concept of nested classes. – Sergey Kalinichenko Nov 28 '14 at 03:45