rmn190 said:
Hi
When a write an inner class inside a method , it can access the
variables in the enclosing method if and only if they are final ...
Why is the compiler enforcing this ??
What might be the reason for java doing this ?? Is it that these Local
Variables will be cached for Inner class usage ??
Thanks a lot in advance!
I think it's mostly just the issue that the stack frame where the local
variables live won't stay around as long as the inner class object created
will live. This means it can't work unless the compiler creates code to
allocate a new hidden object to hold the local variables instead of putting
them on the stack so that the local variables could live for as long as the
inner class object lives.
Just because the compiler won't do it for you doesn't mean you can't do it
for yourself like this:
instead of doing:
void someMethod(int a)
{
int b;
int c;
b = a + 2; // use local vars in method
c = b + 1;
new Inner() {
void method() {
System.out.prinln(a, b, c); // use local vars in inner class
}
}
}
Do it like this:
class LocalVars {
int a;
int b;
int c;
}
void someMethod(int a)
{
LocalObject locals = new LocalObject();
locals.a = a;
locals.b = locals.a + 2; // use local vars in method
locals.c = locals.b + 2;
new Inner() {
LocalVars locals;
void setLocal(LocalVars locals) {
this.locals = locals;
}
void method()
{
System.out.prinln(locals.a, locals.b, locals.c); // use local vars
}
}.setLocal(locals);
}
The second example is what the compiler would have to do for you every time
you accessed local variables from within an inner class. Any variable you
access would have to be moved into a local variable object and shared by
both the inner class and the outer method. That local variable object
would live as long as the method was active, or as long as the inner object
was still alive - whichever lived longer.
In practice, when we need to pass local data into the inner class, we don't
normally create yet another object to hold the local vars but just create
more local vars in the inner class and create setter methods so we can pass
local data into the inner class from the method which created it. Or we put
the data into instance vars of the outer class and make the inner class
access the data in the instance vars instead of accessing local vars.
I'm not sure if Patricia's example of the problems that can arise is really
all that important. That type of problem can happen no matter how you pass
the data into the inner class.
It's really just a question of whether you want the compiler creating
hidden objects for you without it being obvious in the code you have asked
it to do that. Stack frames are expected to go away when the method ends,
but to make this work, stack frames would end up living much longer (or at
least the part which was touched by the inner class). If you create a new
inner class object every time a method is called, the part of the stack
frame which the inner class touched would have to live on as well. It adds
a new dimension of behind-the-scene complexity which is questionable.
The other option is for the compiler to do what it's doing now - treating
the local vars as constants which get compiled into the inner class code or
cached in the inner class object, but do it without the restriction of the
var being final. This means it makes a copy of the current values of the
local variables at the time the inner class object is created. That could
work as well, but again, it creates confusion because syntactically that's
not what people would expect to be happening. They would expect that if
you had a long lived method that the method and the inner class object
would be accessing the same variable instead of different copies of it. So
that's why they put the final restriction on it - to make it clear because
of how it's implemented, that the inner class and outer method are not in
fact accessing the same variable even though syntactically it looks as if
they are.