Java 如果是单线程的,可以在最终类的构造函数中添加此侦听器吗?

Java 如果是单线程的,可以在最终类的构造函数中添加此侦听器吗?,java,constructor,this,listener,final,Java,Constructor,This,Listener,Final,我继承了一个大型Swing应用程序。考虑它的GUI主窗口类的裸版本: import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.SwingUtilities; final class ListenerExa

我继承了一个大型Swing应用程序。考虑它的GUI主窗口类的裸版本:

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

final class ListenerExample1 extends JFrame implements ActionListener {

    private final JButton button = new JButton("Click me");
    private int clickCount = 0;

    public static void main(String... args) throws Exception {
        SwingUtilities.invokeAndWait( () -> {
            ListenerExample1 instance = new ListenerExample1();
            instance.setVisible(true);
            instance.pack();
        } );
    }

    ListenerExample1() throws IllegalStateException {
        if (!EventQueue.isDispatchThread()) throw new IllegalStateException("the current thread (" + Thread.currentThread().toString() + ") is not EventQueue's dispatch thread");

        add(button);
        button.addActionListener(this);
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    }

    @Override public void actionPerformed(ActionEvent e) throws IllegalStateException {
        if (!EventQueue.isDispatchThread()) throw new IllegalStateException("the current thread (" + Thread.currentThread().toString() + ") is not EventQueue's dispatch thread");

        markButtonAsClicked();
    }

    void markButtonAsClicked() throws IllegalStateException {
        if (!EventQueue.isDispatchThread()) throw new IllegalStateException("the current thread (" + Thread.currentThread().toString() + ") is not EventQueue's dispatch thread");

        button.setText("click #" + (++clickCount));
    }

}
此代码从实际应用程序中剥离100次,以实现一个简单的应用程序

IntelliJ正确地警告我这条线

button.addActionListener(this);
导致此引用在施工期间逃逸

我完全明白为什么这通常是件坏事。这在《圣经》中有详细讨论。Goetz关于这一主题的一些专门文章包括和

然而,在这种情况下,它真的不好吗?

特别要注意的是,这个类应该只被一个线程访问。这是因为(EDT)的规则。因此,main方法使用SwingUtilities.invokeAndWait,构造函数和实例方法都检查调用线程是否为EDT

另外,请注意,这个类是final,它排除了子类问题

所以,我认为上面的代码实际上是安全的,尽管IntelliJ发出了警告,但我想知道我是否忽略了一些微妙的问题

我想在实际应用程序的几个构造函数中添加它作为监听器,这是有原因的,在上面的简化代码中并不明显

说到IntelliJ,我注意到上面的代码可以简化。您可以使用lambda隐式创建一个实例内部类,而不是让类实现ActionListener,从而无正当理由地公开actionPerformed方法:

import java.awt.EventQueue;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

final class ListenerExample2 extends JFrame {

    private final JButton button = new JButton("Click me");
    private int clickCount = 0;

    public static void main(String... args) throws Exception {
        SwingUtilities.invokeAndWait( () -> {
            ListenerExample2 instance = new ListenerExample2();
            instance.setVisible(true);
            instance.pack();
        } );
    }

    ListenerExample2() throws IllegalStateException {
        if (!EventQueue.isDispatchThread()) throw new IllegalStateException("the current thread (" + Thread.currentThread().toString() + ") is not EventQueue's dispatch thread");

        add(button);
        button.addActionListener( (e) -> markButtonAsClicked() );
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    }

    void markButtonAsClicked() throws IllegalStateException {
        if (!EventQueue.isDispatchThread()) throw new IllegalStateException("the current thread (" + Thread.currentThread().toString() + ") is not EventQueue's dispatch thread");

        button.setText("click #" + (++clickCount));
    }

}
令我惊讶的是,IntelliJ没有警告新的lambda生产线

button.addActionListener( (e) -> markButtonAsClicked() );
再次导致this引用在构造期间逃逸——这一行肯定让this逃逸

这只是IntelliJ检查代码中的一个缺陷吗

还是有一些微妙的原因说明lambda代码实际上是安全的?(这个新的lambda代码在这种特殊情况下应该是安全的,原因与上面讨论的原始版本相同。)