Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 808
David K. Avatar asked Nov 29 '22 10:11

David K.


2 Answers

You have to differenciate:

  • Static inner classes have access to all static members outside their declaration.
  • Instance inner classes have access to all class members outside their declaration, AND to final fields in the function they are declared in.

Have in mind that a non-static inner class also has a hidden variable with the instance of the outer class, to access the members there. And that all referenced final fields (therefore they must be final) are copied into the inner class in other hidden member variables when the inner class is instantiated.

Example:

public void doStuff(final int a, int b) {
    final int c; // Can be referenced
    int d;       // Cannot be referenced, not final

    executer.execute( new Runnable() {
        public void run() {
            System.out.println("a: "+a+"  c: "+c);
        }
    }

    b++; // Not final, not referencable
    System.out.println(b);
}
like image 22
Daniel Avatar answered Dec 14 '22 07:12

Daniel


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.

like image 51
Ted Hopp Avatar answered Dec 14 '22 08:12

Ted Hopp