Java scoping rules and inner classes
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.
Scope of private variables within inner classes
The fundamental aspect of this is that inner classes (as opposed to static nested classes) are part of their enclosing class. They aren't separate from it, or from each other. So just like other parts of the enclosing class (constructors and methods) have access to all of its private information, so do all the members of the inner classes. Inner classes are, in some sense, a bit of a fiction that we use as a convenient abstraction mechanism. And since inner classes are part of the enclosing class, their private information is its private information, and so is shared with other inner classes.
Inner Class Enclosing Instance and Scope
Let's say we have a class Foo with a static-nested and inner class(Types of Nested Classes):
public class Foo{
// <---------------------------|
void hello() { // |
System.out.print("Hello");// enclosing scope of InnerFoo
} // |
// <---------------------------|
public class InnerFoo{
void world() {
System.out.print("World");
}
}
// <---------------------------------|
public static class StaticNestedFoo{ //|
void world() { // |
System.out.print("World"); // enclosing scope of InnerFoo
} // |
} // |
// <---------------------------------|
}
As can be seen, the enclosing scope of class InnerFoo is the scope(blocks/methods/types) corresponding to where InnerFoo is declared.
Now, if we want to use the InnerFoo class we would need to:
Foo f = new Foo(); // enclosing instance needed to construct InnerFoo
Foo.InnerFoo ifoo = f.new InnerFoo();
ifoo.world();
As marked in the comment, the enclosing instance is the instance(of Foo
here) we need to create in order to construct the non-static nested class.
Finally, if we have a static nested class, we don't need the enclosing instance of Foo and can reference it directly:
Foo.StaticNestedFoo sfoo = new Foo.StaticNestedFoo();
sfoo.world();
A static member variable/method of a class is shared by all instances of the class, thus directly accessible by the class name. In a similar way a static nested class, can be thought of being independent of any instance, thus not requiring the enclosing instance to construct.
Source Code
Related: What is enclosing scope in Java?, really confused by "enclosing scope" of javascript es6 arrow function
Accessibility and Visibility in Nested Class C++
What you've created here is a nested class: The name of the nested class exists in the scope of the enclosing class, and name lookup from a member function of a nested class visits the scope of the enclosing class after examining the scope of the nested class.
When you refer to x
within Test1::Test2::m()
in your example, the compiler is going to go up the scope chain and find the first x
to be Test1::x
. Because this isn't a static member variable you're getting the error.
If you want to refer to the global x
use ::x
. I modified your example to demonstrate:
#include <stdio.h>
int x = 0;
class Test1{
public:
char *x;
class Test2{
public:
int m(){
return ::x++;
}
};
};
int main() {
printf("x = %d\n", x);
Test1::Test2 foo;
foo.m();
printf("x = %d\n", x);
return 0;
}
This prints:
x = 0
x = 1
$.02 note on style: If you reserve nested classes for simple data containers that only operate on themselves, as is a common best practice, you won't run into this issue.
Shorten Member Function Scope Specifiers (Nested Classes) (C++)
Qualified type names allow you to define a typedef to represent a qualified class name. You can then use the typedef with the :: (scope resolution) operator to refer to a nested class or class member, as shown in the following example:
class outside
{
public:
class nested
{
public:
static int x;
static int y;
int f();
int g();
};
};
int outside::nested::x = 5;
int outside::nested::f() { return 0; };
typedef outside::nested outnest; // define a typedef
int outnest::y = 10; // use typedef with ::
int outnest::g() { return 0; };
However, using a typedef to represent a nested class name hides information and may make the code harder to understand.
Source : https://www.ibm.com/support/knowledgecenter/en/SSPSQF_9.0.0/com.ibm.xlcpp111.aix.doc/language_ref/cplr061.html
Related Topics
Optimizing for Accuracy Instead of Loss in Keras Model
Learning Python from Ruby; Differences and Similarities
What Is Ruby Equivalent of Python's 'S= "Hello, %S. Where Is %S" % ("John","Mary")'
Benchmarks: Does Python Have a Faster Way of Walking a Network Folder
Is There a Static Analysis Tool for Python, Ruby, SQL, Cobol, Perl, and Pl/Sql
Ruby Methods Equivalent of "If a in List" in Python
Bloomberg Server API and Ruby/Python
Pyobjc VS Rubycocoa for MAC Development: Which Is More Mature
Create Static Graphics Files (Png, Gif, Jpg) Using Ruby or Python
Python's Equivalent for Ruby's Define_Method
Python Equivalent of Ruby's .Select
How to Define a Function with Optional Arguments
How to Implement a Tree in Python
Understanding _Getitem_ Method
Failed to Install Python Cryptography Package with Pip and Setup.Py