Search code examples
javainner-classesscoping

Java scoping rules and inner classes


All the crazy Java scoping rules are making my head spin and the public static void nonsense isn't helping matters. So far all the programming languages I have used either lexical scoping or some approximation of it without any access modifiers, i.e. inner stuff captures outer stuff and has access to the outer stuff as long as the inner stuff exists.

So how do I make sense of the scoping rules for inner classes in Java? Do they get access to variables declared in the outer class or is there some weird edge cases I have to worry about because of all the public static private stuff floating around?


Solution

  • Static nested classes1 are exactly like external classes except that they have access to all members of the outer class, regardless of access qualifier. They exist apart from any instance of the outer class, so need a reference to an instance in order to access any instance variables or non-static methods of the outer class.

    Non-static nested classes (called inner classes) come into existence only in the context of an instance of the outer class. When constructed, they have a second this field automatically generated, which you can access from within the inner class using the syntax Outer.this. Each instance of the inner class is enclosed by a single instance of the outer class. Again, all the access privileges of static nested classes apply to inner classes. But since they already have an instance of the outer class available, they can automatically access instance variables and methods of the outer class.

    For a nice (and very detailed) discussion of inner classes and access specifiers, you can read through the Inner Class Specification. It describes, among other things, how a nested class gets access to private members of its outer class(es). A gentler read is the Nested Classes tutorial.

    An off-topic aside: Suppose you have this class structure:

    public class O {
        public O() { ... }
    
        public class I { // an inner class
            public I() { ... }
            ...
        }
        ...
    }
    

    and you've created an instance of O:

    O outer = new O();
    

    Now suppose you want to create an instance of O.I. you can't just use new O.I() because the new instance of I needs to be enclosed by a specific instance of O. For this, Java provides the following syntax:

    O.I inner = outer.new O.I();
    

    Then inner will then have its second this field set to refer to outer.

    Note that this "qualified new operator" syntax is only used for inner classes; it would be unnecessary (in fact, an error) if I were a static nested class.

    1 You'll often come across the phrase "static inner class" (including, embarrassingly, in an earlier version of this answer). This is incorrect terminology. In Java, "inner classes" are specifically non-static nested classes.