[英]Java - How am I accessing non final variables from an anonymous inner class?
如下面的代码所示,我正在从ActionListener匿名内部类访问JLabel。 这不会给我带来任何错误,因此如何允许使用此方法,但是如果JLabel位于INSIDE,则在没有final修饰符的情况下不允许使用该方法?
JLabel e = new JLabel("");
public void myMethod() {
JButton b = new JButton("ok");
b.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
e.setSize(200,200);
}
});
}
如果该变量在方法def内,则它是一个局部变量-并且您要实例化一个对象,该对象将在该方法执行后存在,并且该局部变量的生命周期已经结束(位于该方法的堆栈框架中)在方法返回时销毁)。 为了使它完全起作用,需要一些编译器魔术,并且通常将其称为闭包 ,即使其当前在Java中的实现如此la脚。 编译器实际上将合成一个类,该类实现ActionListener
并具有一个实例变量,该本地变量的值将被复制到该实例变量。
这是Java特有的限制,由于线程安全问题,您只能在final
var上关闭。 这里的故事说,Java开发人员的直觉是,本地var始终是线程安全的-它不能在方法执行过程中进行更改(该方法未明确进行任何更改),可以如果没有非Datavars,等等。如果您可以关闭非最终变量,则可能会违反该规则,因为该关闭可以与当前执行的方法并行执行并更改该变量。 这将导致一些非常违反直觉的行为。
但是,有一个(有些la脚)解决方法:
public void myMethod() {
final JLabel[] e = {new JLabel("")};
JButton b = new JButton("ok");
b.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent arg0) {
e[0].setSize(200,200);
}});
}
e
现在是一个单元素数组,它驻留在堆上,并且不会被方法的stackframe破坏。 您还可以凭直觉看到现在绝对不是线程安全的,并且侦听器可以轻松地将e[0]
的值更改为完全不同的值,并且此处显示的方法将观察到该更改,而无需使用显式的突变代码。它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.