为什么变量必须在匿名方法中是最终的,而类字段则不是

时间:2013-08-14 11:46:41

标签: java attributes anonymous-methods

如果我有这个匿名方法,我应该声明x变量为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();
            }
          });
}

但是,如果loader是一个类字段,则没有必要将其声明为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;
        }
}

有没有人知道为什么他们保证局部变量在被访问时不会改变但是不为类字段做?

4 个答案:

答案 0 :(得分:8)

加入java docs

  

匿名类可以访问其封闭类的成员   匿名类无法访问其封闭范围中未声明为final或者有效final的局部变量(有效最终意味着变量在初始化后永远不会更改。方法参数通常是最终的。)

     

如果我们对本地课程的实施方式有所了解,那么这种限制的原因就显而易见了。匿名本地类可以使用局部变量,因为编译器会自动为类提供一个私有实例字段来保存类使用的每个局部变量的副本。编译器还为每个构造函数添加隐藏参数,以初始化这些自动创建的私有字段。因此,本地类实际上并不访问本地变量,而只是它们自己的私有副本。这种方法可以正常工作的唯一方法是将局部变量声明为final,以确保它们不会改变。有了这种保证,本地类就可以确保其变量的内部副本能够准确地反映实际的局部变量。

答案 1 :(得分:3)

局部变量在堆栈中分配,在testMethod()之后将超出范围。使变量最终确保只需将对它的引用传递给匿名类即可。如果它不是最终的,那么稍后在testMethod()中对其进行的分配可能会在以后混淆结果时更改该值。 (用户可能期望使用后来分配的值,但这是不可能的。)

父类的字段可以通过匿名类的父引用访问,因此任何以后的分配都可以毫不费力地处理。

答案 2 :(得分:1)

在java中查看Lambdas和Conjures。

匿名内部类没有相关信息 - 你必须指明它是最终的,所以你可以保证它的存在。

这可能与ListLoader的性质有关,但我对使用此库没有经验。

我希望我指出你正确的方向。

答案 3 :(得分:1)

匿名类通过构造函数隐式获取局部变量。那就是他们获得他们使用的本地变量的副本。因此,如果我们在主代码中更改了变量值,则匿名类将不会看到此更改。声明本地变量最终有助于避免这种模糊性。