在下面的示例中,通过将参数int i
设置为final
class Miner1
{
Miner getMiner(final int i) {
return new Miner() {
public void perform_work() {
System.out.println(i);
}
};
}
interface Miner { void perform_work(); }
否则,如果没有像前面的例子那样设置为final,则不会编译。
有人知道为什么吗?即使没有final
,它也应该在范围内,因为卷曲括号尚未关闭。
提前致谢。
答案 0 :(得分:4)
答案 1 :(得分:3)
答案 2 :(得分:2)
Java只允许从方法/构造函数中定义的匿名类引用最终变量/参数。这是为了使代码的行为更直观。变量/参数的值在创建实例时通过隐藏的构造函数参数传递给匿名类的实例,因此匿名类的实例无法跟踪变量的进一步更改。如果允许访问非最终变量,可以写下以下内容:
int a = 5;
Thread t = new Thread ()
{
@Override
public void run ()
{
System.out.println (a); // This will print 5, rather than 6!
}
};
a = 6;
t.start ();
期待打印6
。要理解为什么上面的代码将打印5
,请注意此代码等同于以下内容:
class MyThread extends Thread
{
int _a;
public MyThread (int a)
{
this._a = a;
}
@Override
public void run ()
{
System.out.println (_a);
}
}
int a = 5;
Thread t = new MyThread (a); // Value `5` is passed
a = 6;
t.start (); // Value `5` passed to the constructor earlier is printed here
答案 3 :(得分:0)
这是因为,在Java中,匿名内部类只能访问最终的局部变量和类的字段
现在的问题是为什么?
这是因为方法的局部变量(在您的情况下为getMiner
)存在于堆栈中,并且仅在方法的生命周期中存在。局部变量的范围仅限于声明变量的封闭方法。当方法结束时,堆栈框架被烧掉,变量是历史。但即使在方法完成后,在其中创建的内部类对象仍可能在堆上存活。例如,如果通过Miner
获得的匿名内部类getMiner
的引用被传递到代码的其他位置并在那里使用,那么由于局部变量已经被炸毁,这将是一个奇怪的情况。那个对象。这个问题的一个解决方案可能是匿名内部类对象制作局部变量的副本。但同样,它不能保证匿名内部类对象将看到该变量的最新值,因为局部变量容易发生变化。
但是如果局部变量是最终的,它确保变量值在初始化后不会在任何条件下发生变化,因此方法本地内部类只能复制它以供私人使用,即使在从堆栈中删除原始值之后,它也会存在。