6

如果我有这个匿名方法,我应该将 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

4 回答 4

9

根据java文档

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

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

于 2013-08-14T11:53:05.503 回答
5

局部变量是在栈中分配的,在testMethod(). 将变量设为 final 可确保只需将对它的引用传递给匿名类即可。如果它不是最终的,那么稍后对它的赋值testMethod()可能会在以后更改值,从而产生令人困惑的结果。(用户可能期望使用稍后分配的值,但这是不可能的)。

但是,可以通过匿名类的父引用访问父类的字段,因此可以处理任何以后的分配而不会混淆。

于 2013-08-14T11:53:12.970 回答
1

看看 java 中的 Lambdas 和 Conjures。

匿名内部类周围没有任何信息——你必须指定它是最终的,这样你才能保证它的存在。

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

我希望我为您指明了正确的方向。

于 2013-08-14T11:52:03.750 回答
1

匿名类通过构造函数隐式获取局部变量。也就是说,他们获得了他们使用的本地变量的副本。因此,如果我们在主代码中更改变量值,匿名类将不会看到这种变化。声明 local vars final 有助于避免这种歧义。

于 2013-08-14T11:52:56.643 回答