Reputation: 170
While going through Oracle docs reading about Nested classes, I found this piece of code whose output I could not understand. Can someone please explain this ?
public class ShadowTest {
public int x = 0;
class FirstLevel {
public int x = 1;
void methodInFirstLevel(int x) {
System.out.println("x = " + x);
System.out.println("this.x = " + this.x);
System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);
}
}
public static void main(String... args) {
ShadowTest st = new ShadowTest();
ShadowTest.FirstLevel fl = st.new FirstLevel();
fl.methodInFirstLevel(23);
}
}
The following is the output of this example:
x = 23
this.x = 1
ShadowTest.this.x = 0 //why is 0 printed here? why not 1 because "this" is the object of FirstLevel class.
The original code can be found here
Upvotes: 4
Views: 181
Reputation: 79
I feel like this wasn't fully explained beyond the documentation found here so I am going to try to go into more detail based on my recent understanding.
I've changed the name of the ShadowClass
outer class to NestedClasses
and changed the variables from type int
to type String
.
Here is an example of adding a second nested class within the first nested class to show how NestedClasses.this.x
continues to behave in deeper layers of classes.
public class NestedClasses {
public String x = "outer class variable";
class FirstLevel {
public String x = "first level class variable";
void methodInFirstLevel(String x) {
System.out.println("methodInFirstLevel:");
System.out.println("x = " + x);
System.out.println("this.x = " + this.x);
System.out.println("NestedClasses.this.x = " + NestedClasses.this.x);
}
class SecondLevel {
public String x = "second level class variable";
void methodInSecondLevel(String x) {
System.out.println("methodInSecondLevel:");
System.out.println("x = " + x);
System.out.println("this.x = " + this.x);
System.out.println("NestedClasses.this.x = " + NestedClasses.this.x);
System.out.println("FirstLevel.this.x = " + FirstLevel.this.x);
System.out.println("NestedClasses.FirstLevel.this.x = " + NestedClasses.FirstLevel.this.x);
}
}
}
public static void main(String[] args) {
NestedClasses st = new NestedClasses();
NestedClasses.FirstLevel fl = st.new FirstLevel();
NestedClasses.FirstLevel.SecondLevel sl = fl.new SecondLevel();
fl.methodInFirstLevel("first level method arg");
System.out.println();
sl.methodInSecondLevel("second level method arg");
}
}
Output:
methodInFirstLevel:
x
= first level method arg
this.x
= first level class variable
NestedClasses.this.x
= outer class variable
methodInSecondLevel:
x
= second level method arg
this.x
= second level class variable
NestedClasses.this.x
= outer class variable
FirstLevel.this.x
= first level class variable
NestedClasses.FirstLevel.this.x
= first level class variable
Each of the three instantiated objects (st
, fl
, sl
) contain a pointer to different memory space in the heap where the value of x
can be found. I believe the compiler is searching "backwards" towards the outermost layer to find the first matching class when it see's a class name prefixed to this
in a nested class. The first matching class it finds is the class it will refer to when determining which object instantiation it needs to search to find x
. This would mean NestedClasses.FirstLevel.this.x
is really taking two steps backward and one step forward to determine which memory space to look at in the heap, i.e. which memory space x
references.
Summery:
NestedClasses.this.x
NestedClasses
tells the JVM which class is being used, this class must be reachable from the current scope.this
keyword tells the JVM to look at the memory space of an instantiated object of the class being referred to, rather than the memory space of the class object itself (which is used for static members of the class). More specifically, this
will reference the instantiation of the outer class that was used (and required) to instantiate the non-static inner class.x
appended to this
tells the JVM what to search for in the memory space it is looking at.Upvotes: 1
Reputation: 394106
The local variable x
shadows this.x
and ShadowTest.this.x
.
The instance variable of the inner class (this.x
) shadows the instance variable of the enclosing class (which can be accessed by ShadowTest.this.x
).
System.out.println("x = " + x); // prints the local variable passed to the method
System.out.println("this.x = " + this.x); // prints the instance variable of the inner class
System.out.println("ShadowTest.this.x = " + ShadowTest.this.x); // prints the instance variable of the enclosing class instance
Upvotes: 6