Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Oracle Java tutorial - static classes - possible error in tutorial

Tags:

java

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

like image 539
Eliyahu Machluf Avatar asked Sep 02 '18 11:09

Eliyahu Machluf


People also ask

Can classes in Java be static?

Java supports Static Instance Variables, Static Methods, Static Block, and Static Classes. The class in which the nested class is defined is known as the Outer Class. Unlike top-level classes, Inner classes can be Static. Non-static nested classes are also known as Inner classes.

How do I access static nested class?

And like static class methods, a static nested class cannot refer directly to instance variables or methods defined in its enclosing class: it can use them only through an object reference. They are accessed using the enclosing class name. To instantiate an inner class, you must first instantiate the outer class.

Why classes are not static in Java?

Because it doesn't add any meaning. 'static' has a meaning when applied to nested classes. It has no meaning on an outer class. So you can't specify it.

Can methods in all nested classes can be declared static?

Methods in all nested classes can be declared static. All nested classes can be declared static. Static member classes can contain non-static methods.


2 Answers

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.

like image 150
Boann Avatar answered Nov 15 '22 18:11

Boann


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.

like image 43
Hovercraft Full Of Eels Avatar answered Nov 15 '22 19:11

Hovercraft Full Of Eels