Reputation: 1264
I'm familiar that all local variables will be stored inside stack memory and objects and static variables will be stored in heap. But then when I came across the following code which confuses me.
public class Outer {
private int a =10;
public void outerMethod() {
int x = 30;
class Inner {
private int b = 20;
public void innerMethod() {
System.out.println("The Value of a is: "+a);
System.out.println("The Value of b is: "+b);
System.out.println("The Value of x is: "+x);
}
};
Inner inner = new Inner();
inner.innerMethod();
}
}
The above code runs fine. But my question here is x is a local variable of outerMethod(). And when we create an object of Outer class, and invoke outerMethod() on it, x will be stored inside a stack frame, and I'm also defining a class definition of Inner class and creating object of it, then I'm invoking innerMethod() on it.
So that Inner Class's object must be stored inside heap. If that's the case then how could it access x??
Upvotes: 1
Views: 1253
Reputation: 4111
It's true that the Inner
class will be compiled to a separate class in the same package. You are correct that normally you shouldn't have access to private methods and fields of the Outer
class.
But, the compiler will create some synthetic package-private methods in the bytecode-level to achieve this functionality. Now, your Inner
class can access these auto-generated (hidden from you) package-private
(with no access modifier) methods.
Upvotes: 1
Reputation: 9945
Inner
can only access x
if x
is final (or, from Java 8 effectively final). Under the covers, the compiler will notice which outer variables are used by the Inner
object and will pass them into the Inner
constructor (these will be synthetic constructor parameters - generated by the compiler, so you will not see them). Then they will become final (again, synthetic = generated and hidden from you) fields of the Inner
class. When you refer to x
in the Inner
class code, the compiler will substitute it with a reference to the synthetic x
field in the Inner
class where the value was copied.
You can see more details with this useful command:
javac -d . -XD-printflat MyFile.java
Will generate the Java code corresponding to the actual bytecode:
class Outer {
/*synthetic*/ static int access$000(Outer x0) {
return x0.a;
}
Outer() {
super();
}
private int a = 10;
public void outerMethod() {
int x = 30;
/*synthetic*/ {
}
;
Outer$1Inner inner = new Outer$1Inner(this, x);
inner.innerMethod();
}
}
class Outer$1Inner {
/*synthetic*/ final Outer this$0;
/*synthetic*/ final int val$x;
Outer$1Inner(final Outer this$0, /*synthetic*/ final int val$x) {
// Notice the synthetic references to the surrounding Outer object
// and to the x local variable
// Both become fields of Inner
this.this$0 = this$0;
this.val$x = val$x;
super();
}
private int b = 20;
public void innerMethod() {
System.out.println("The Value of a is: " + Outer.access$000(this$0));
System.out.println("The Value of b is: " + b);
System.out.println("The Value of x is: " + val$x);
}
}
You can also notice how Outer.a
is accessed - since Inner
is compiled to a "plain old Java class" it has to respect the visibility modifiers, so the JVM would not allow for direct access to the private field Outer.a
. However, during compilation, the compiler will notice that you want to access this field from Inner
, and since it's an inner class, will generate an accessor method Outer.access$000()
. Since Inner
has a reference to the Outer
object, it can call Outer.access$000(referenceToOuter)
and get the value of Outer.a
.
Upvotes: 3
Reputation: 8354
Inner
class object has a link to your Outer
class object. what Inner
is doing is essentially capturing or closing your local variable x
,thereby increasing it's "lifetime" and thus your Inner
class can access x
.
Upvotes: 0