11
votes

I'm new to Java, learning Java from the Oracle Java tutorial. I'm now learning about nested classes, static classes and inner classes. I found the following explanation which seems odd, and I think it is wrong.

From: https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html

A nested class is a member of its enclosing class. Non-static nested classes (inner classes) have access to other members of the enclosing class, even if they are declared private. Static nested classes do not have access to other members of the enclosing class

The last sentence "Static nested classes do not have access to other members of the enclosing class" is strange, but may refer to instance members, saying the static class is like a static method, having no access to instance variables. But the next note is even stranger:

Note: A static nested class interacts with the instance members of its outer class (and other classes) just like any other top-level class. In effect, a static nested class is behaviorally a top-level class that has been nested in another top-level class for packaging convenience.

This seems odd, as it implies that a static class cannot access private instance members of the outer class. I've written the following code which compiles and runs, and demonstrates that a static class can access outer instance private variables.

public class A {

    private int x;
    static private int y;


    static public class B{

        static void doSomething(){
            y++;
            System.out.println("y is now " + y );
        }

        static void doSomethingElse(A a)
        {
            a.x++;
            System.out.println("a.x is " + a.x );
        }
    }
}

// ------

public class Main {

    public static void main(String[] args){
        A a = new A();
        A.B b = new A.B();
        b.doSomething();
        b.doSomethingElse(a);
    }
}

Is this a mistake in the tutorial, or am I maybe not understanding something well? Thanks

2
And hint: these tutorials are used by thousands of people. They are written by absolute experts, and probably undergo heyvy reviews. The content may be not always clear, but for a Java newbie, the chances of finding an error in there is very small. Meaning: it is a safe bet that the tutorial is right :-)GhostCat
Yes. this is a reasonable comment. I'm posting questions here, to better understand things which are not clear to me. however, from time to time, there are errors/oversights even at this tutorial. very strange, but there are some. see stackoverflow.com/questions/52095760/… and stackoverflow.com/questions/51634863/…Eliyahu Machluf
No, they (the tutorials) are not perfect, but I know from my own experience that 99.999% of the time where I've thought I've found an error in them (or in Java itself), the error has been in my own understanding and not the tutorial. Perhaps your numbers are better, but that's my own experience.Hovercraft Full Of Eels

2 Answers

7
votes

Is this a mistake at the tutorial, or maybe I'm not understanding somwthing well?

The error is in your understanding, and the tutorials are correct. Nowhere within your nested static class is there any direct manipulation of the instance fields of the outer class. I'm talking about these fields without an instance attached -- nowhere can you directly manipulate x without having it attached to an A instance.

So you can do this:

static void doSomethingElse(A a) {
    a.x++;  // x is part of the A instance passed into a parameter
    System.out.println("a.x is " + a.x );
}

but you can't do this:

static void doSomethingElse2() {
    x++;
    System.out.println("x is " + x );
}

And this code would be the same if B were static nested or a stand-alone non-nested class.


You ask:

"A static nested class interacts with the instance members of its outer class just like any other top-level class"?

Exactly as is shown above -- a non-static nested class can directly interact with the a field (as doSomethingElse2() shows) without need of a supporting A instance, while both a static nested class and a stand alone class cannot. They both require the separate A instance, here which is passed into your doSomethingElse(A a) method parameter.


The main difference between a static nested and a stand-alone is that the former, the nested class, has access to private members of the outer class while the stand-alone does not. Perhaps this is your source of confusion.

4
votes

Is this a mistake in the tutorial, or am I maybe not understanding something well?

You are understanding perfectly. The tutorial page is misleading, at best.

There are two separate notions going on here:

  1. Whether you have permission to access a thing within the rules of Java access control (e.g., private, package-private, protected, public).

  2. The meaning of "static". An instance of an "inner" nested class is always associated with an instance of the enclosing class (storing a reference to the enclosing class instance in a hidden instance field of the inner class). A "static" nested class doesn't have that.

The tutorial page is confusing the two notions.

A nested class is a member of its enclosing class.

Yep.

Non-static nested classes (inner classes) have access to other members of the enclosing class, even if they are declared private. Static nested classes do not have access to other members of the enclosing class.

Nope.

By supplying the instance yourself, you see that static classes do indeed have access to members of the enclosing class, including private instance fields, hence why a.x++; in your example compiles. That's access.

By using the words "access" and "private", the paragraph strongly suggests it is talking about access control within the definition given in the Java Language Specification. But it isn't. It is only trying to explain notion #2, about how instances of enclosing classes are associated with nested classes. And even then, it's still wrong, because static nested classes certainly have access to static members of the enclosing class, which the paragraph says they don't. Whoever wrote that page was sloppy.

Note: A static nested class interacts with the instance members of its outer class (and other classes) just like any other top-level class. In effect, a static nested class is behaviorally a top-level class that has been nested in another top-level class for packaging convenience.

This paragraph is still talking about what static means. It is not trying to say anything about access control, although it has the potential to be misunderstood.


Here is the correct access control rule, given by JLS§6.6.1 – Determining Accessibility:

[If] the member or constructor is declared private, [..] access is permitted if and only if it occurs within the body of the top-level class (§7.6) that encloses the declaration of the member or constructor.

That definition is surprisingly short, but it covers everything relevant here.

It means that all nested classes (because they are "within the body of the top-level class") have access to all members and constructors of the enclosing class, regardless of whether the nested class is static or instance, and regardless of whether the accessed thing is static or instance.

Further, all nested classes also have access to all members and constructors of all other nested classes within the same top-level class.

And the top-level class has access to all members and constructors of all classes nested within it.

The sentence of the JLS I quoted refers to private access. But if the member or constructor is not private, then its access level can only be more permissive, at least package access, and classes enclosed within the same top-level type are inevitably in the same package too, so they would be accessible to each other even without special treatment.

Basically, the top-level (non-enclosed) class and everything within it constitute a nest. Everything within that nest can access everything else within it, in principle. If it's an instance member, you also need to somehow obtain an instance first, but that's always true.