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

StackOverflow https://stackoverflow.com/questions/18230870

Вопрос

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?

Это было полезно?

Решение 2

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.

Другие советы

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.

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.

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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top