Anonymous inner Classes accessing final variables?

R

rmn190

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!
 
P

Patricia Shanahan

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!

The inner class object may still exist long after the method has
completed. The value it sees for local variables is the value they had
when the object was created.

If non-final variables had been permitted, people would have wasted time
debugging obscure run-time failures due to a variable having changed value.

Note that you can always have a final variable that exists only for the
sake of the inner class object:

{
final int innerValue = someChangingVar;
....
}

Patricia
 
G

getsanjay.sharma

The inner class object may still exist long after the method has
completed. The value it sees for local variables is the value they had
when the object was created.

If non-final variables had been permitted, people would have wasted time
debugging obscure run-time failures due to a variable having changed value.

Hello Patricia,

Can you give a real time example on what kind of complexities can
arise if non-final variables were permitted inside inner classes /
anonymous classes?

Thanks and regards,
/~STS
 
D

Daniel Pitts

Hello Patricia,

Can you give a real time example on what kind of complexities can
arise if non-final variables were permitted inside inner classes /
anonymous classes?

Thanks and regards,
/~STS
I sure can. Imagine this situation:

public void stuff() {
String foo = "Hello";
Runnable r = new Runnable() {
public void run() {
while (foo.size() < 1000) {
foo += ".";
}
}
};
new Thread(r).start();
System.out.println(foo);
foo = null;
return r;
}

So, what is the behavior of this snippet when someone calls "stuff"? Is
it obvious or did you have to think about it for a while? Imagine that
the runnable returned was used from some other place in this class?
 
C

Curt Welch

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.
 
W

Wayne

Curt said:
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.
...

Does anyone here know how JavaScript implements closures? Just curious.

-Wayne
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,736
Latest member
AdolphBig6

Latest Threads

Top