Java 如果是单线程的,可以在最终类的构造函数中添加此侦听器吗?
我继承了一个大型Swing应用程序。考虑它的GUI主窗口类的裸版本: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
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代码在这种特殊情况下应该是安全的,原因与上面讨论的原始版本相同。)