简体   繁体   English

Java-如何从匿名内部类访问非最终变量?

[英]Java - How am I accessing non final variables from an anonymous inner class?

As you can see in the following code, I am accessing a JLabel from the ActionListener anonymous inner class. 如下面的代码所示,我正在从ActionListener匿名内部类访问JLabel。 This provides me with no errors, so how is this allowed but if the JLabel was INSIDE the method is is not allowed without the final modifier? 这不会给我带来任何错误,因此如何允许使用此方法,但是如果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);

                }

            });

        }

If the variable is inside the method def, then it's a local variable -- and you are instantiating an object that will exist after that method's execution, and with it the lifetime of that local variable, has ended (it's in the method's stackframe that gets destroyed upon method return). 如果该变量在方法def内,则它是一个局部变量-并且您要实例化一个对象,该对象将在该方法执行后存在,并且该局部变量的生命周期已经结束(位于该方法的堆栈框架中)在方法返回时销毁)。 For this to work at all some compiler magic is required, and this is usually called a closure , even if its current implementation in Java is so lame. 为了使它完全起作用需要一些编译器魔术,并且通常将其称为闭包 ,即使其当前在Java中的实现如此la脚。 The compiler will actually synthesize a class that implements ActionListener and has an instance variable to which the local variable's value will be copied. 编译器实际上将合成一个类,该类实现ActionListener并具有一个实例变量,该本地变量的值将被复制到该实例变量。

It is a restriction specific to Java that you can only close over final vars due to thread-safety concerns. 这是Java特有的限制,由于线程安全问题,您只能在final var上关闭。 The story here goes that it is ingrained in the intuition of a Java developer that a local var is always thread-safe -- it can't change in the middle of method's execution (with no change done explicitly by that method), there can be no dataraces on it, etc. This would be violated if you could close over non-final vars as that closure could be executed in parallel with the currently executing method and change that var. 这里的故事说,Java开发人员的直觉是,本地var始终是线程安全的-它不能在方法执行过程中进行更改(该方法未明确进行任何更改),可以如果没有非Datavars,等等。如果您可以关闭非最终变量,则可能会违反该规则,因为该关闭可以与当前执行的方法并行执行并更改该变量。 That would lead to some very counterintuitive behavior. 这将导致一些非常违反直觉的行为。

There is, however, a (somewhat lame) workaround: 但是,有一个(有些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 is now a one-element array, which resides on the heap and doesn't get destroyed with the method's stackframe. e现在是一个单元素数组,它驻留在堆上,并且不会被方法的stackframe破坏。 You can also apply your intuition to see that now it's definitely not thread-safe and that listener could easily change the value of that e[0] to something completely different, and the method shown here would observe that change with no explicit mutation code in it. 您还可以凭直觉看到现在绝对不是线程安全的,并且侦听器可以轻松地将e[0]的值更改为完全不同的值,并且此处显示的方法将观察到该更改,而无需使用显式的突变代码。它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM