Why variables have to be final in anonymous methods and class fields don't [duplicate]
Asked Answered
S

4

6

If I had this anonymous method I should declare x variable as final.

private void testMethod (ListField<BeanModel> listField){

     final ListLoader<BeanModel> loader = new PagedListLoader<BeanModel>();
     listField.addListener(Events.Attach, new Listener<ListViewEvent<BeanModel>>() {

            @Override
            public void handleEvent(ListViewEvent<BeanModel> be) {
                loader.load();
            }
          });
}

However, if loader was a class field, it wouldn't be necessary to declare it as final:

public class testClass{

    private ListLoader<BeanModel> loader = new PagedListLoader<BeanModel>();

    private void testMethod (ListField<BeanModel> listField){
        listField.addListener(Events.Attach, new Listener<ListViewEvent<BeanModel>>() {

                    @Override
                    public void handleEvent(ListViewEvent<BeanModel> be) {
                        loader.load();
                    }
                  });

        //Could I modify loader's reference here, before the method executes?
        //loader = null;
        }
}

Does anyone know the reason why they guarantee local variables not to change when they're accessed but don't do it for class fields?

Sianna answered 14/8, 2013 at 11:46 Comment(4)
@jlordo. Not exactly. That post doesn't talk about the fields, just the local variables.Spearmint
The same principle applies. It's an (anonymous) inner class that has a reference to it's enclosing instance of the outer class and therefore can access it's fields.Man
another one here #1300337Charleycharlie
I think I didn't explain it correctly. My question is about fields, not local variablesSianna
D
5

The local variable is allocated in the stack, and it will fall out of scope after testMethod(). Making the variable final ensures that it is ok to just pass a reference to it to the anonymous class. If it was not final, a later assignment to it in testMethod() could change the value later with confusing results. (The user might expect the later assigned value used, but that would be impossible).

A field of the parent class, however can be accessed through the parent reference of the anonymous class, so any later assignments can be handled without confusion.

Decline answered 14/8, 2013 at 11:53 Comment(2)
But, what if the field's content has changed in the meantime?Sianna
@AminAbu-Taleb Since the access goes through the parent reference, the inner class can always use the latest value.Decline
L
9

Accroding to java docs

An anonymous class has access to the members of its enclosing class.
An anonymous class cannot access local variables in its enclosing scope that are not declared as final or effectively final (Effectively final means that the variable is never changed after it is initialized. Method parameters are often effectually final.)

The reason for this restriction becomes apparent if we shed some light on how local classes are implemented. An anonymous local class can use local variables because the compiler automatically gives the class a private instance field to hold a copy of each local variable the class uses. The compiler also adds hidden parameters to each constructor to initialize these automatically created private fields. Thus, a local class does not actually access local variables, but merely its own private copies of them. The only way this can work correctly is if the local variables are declared final, so that they are guaranteed not to change. With this guarantee in place, the local class is assured that its internal copies of the variables accurately reflect the actual local variables.

Lubric answered 14/8, 2013 at 11:53 Comment(2)
That's what I can't understand. Why do they want to guarantee local variables not to change and don't do that on class fields?Sianna
Think what will happen if local variables fall out of scope? For instance suppose you submitted a few future tasks using some local variables to start after 2 hrs from now and current method has exited. How will you get back to those original values as they are gone from stack?Allanite
D
5

The local variable is allocated in the stack, and it will fall out of scope after testMethod(). Making the variable final ensures that it is ok to just pass a reference to it to the anonymous class. If it was not final, a later assignment to it in testMethod() could change the value later with confusing results. (The user might expect the later assigned value used, but that would be impossible).

A field of the parent class, however can be accessed through the parent reference of the anonymous class, so any later assignments can be handled without confusion.

Decline answered 14/8, 2013 at 11:53 Comment(2)
But, what if the field's content has changed in the meantime?Sianna
@AminAbu-Taleb Since the access goes through the parent reference, the inner class can always use the latest value.Decline
G
2

Anonymous classes get local variables implicitly through constructors. That is they get copies of local vars they use. So if we changed variable value in the main code the anonymous class would not see this change. Declaring local vars final helps avoid this ambiguity.

Guide answered 14/8, 2013 at 11:52 Comment(0)
C
1

Have a look at Lambdas and Conjures in java.

An anonymous inner class has no information around it - you have to specify that it is final so you can guarantee its existence.

This could be something to do with the nature of a ListLoader but I am unexperienced with using this library.

I hope I pointed you into the right direction.

Chelsiechelsy answered 14/8, 2013 at 11:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.