此问题已经在这里有了答案:
如果我有此匿名方法,则应将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();
}
});
}
但是,如果加载器是一个类字段,则不必将其声明为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;
}
}
有人知道为什么保证局部变量在访问时不会改变,但不对类字段进行改变的原因吗?
局部变量在堆栈中分配,在testMethod()
之后将超出范围。将变量设置为final可以确保将对它的引用传递给匿名类是可以的。如果不是最终值,则以后在testMethod()
中对其进行赋值可能会稍后更改该值,从而导致结果混乱。 (用户可能期望使用后来分配的值,但这是不可能的。)>
但是,可以通过匿名类的父引用访问父类的字段,因此以后的任何分配都可以处理而不会引起混淆。
根据java docs
匿名类可以访问其封闭类的成员。匿名类无法在其封闭范围内访问未声明为final或有效地不是final的局部变量(有效地final表示变量在初始化后从未更改。方法参数通常实际上是final。)
如果我们对局部类的实现方式有了一些了解,那么这种限制的原因就显而易见了。匿名本地类可以使用本地变量,因为编译器会自动为该类提供一个私有实例字段,以保存该类使用的每个本地变量的副本。编译器还将隐藏参数添加到每个构造函数中,以初始化这些自动创建的私有字段。因此,局部类实际上并不访问局部变量,而只是访问它们自己的私有副本。唯一可以正常工作的方法是将局部变量声明为final,这样可以保证它们不会更改。有了此保证,就可以确保局部类的变量的内部副本准确反映实际的局部变量。
看看Java中的Lambda和Conjures。
匿名内部类没有周围的信息-您必须指定它是最终的,因此可以保证它的存在。
这可能与ListLoader
的性质有关,但是我对使用此库没有经验。
希望我指出正确的方向。
匿名类通过构造函数隐式获取局部变量。那就是他们得到他们使用的本地变量的副本。因此,如果我们在主代码中更改了变量值,则匿名类将不会看到此更改。声明local vars final有助于避免这种歧义。