添加 PropertyChangeListener 导致 java.lang.NullPointerException
Adding a PropertyChangeListener leads to java.lang.NullPointerException
我刚开始使用 Netbeans 和 PropertyChangeListeners,在 Java bean 中实现 PropertyChangeSupport 时,我遇到了同样(对我来说)奇怪的行为。
所以我有一个名为 TTTCell 的 bean,我在其中初始化了一个 PropertyChangeSupport 变量。然后我实现了维护 属性 更改侦听器列表的功能。
package tttboard;
import java.awt.Color;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
import java.beans.VetoableChangeSupport;
public class TTTCell extends javax.swing.JPanel {
public static enum State
{
INITIAL,
PLAYER_X,
PLAYER_O,
WON,
DISABLE
}
// Variables
private State state;
private PropertyChangeSupport propChange = new PropertyChangeSupport(this);
public TTTCell() {
initComponents();
state = State.INITIAL;
}
@Override
public void addPropertyChangeListener(PropertyChangeListener listener) {
propChange.addPropertyChangeListener(listener); // it depends on that line whether the erroroccurs or not
}
@Override
public void removePropertyChangeListener(PropertyChangeListener listener) {
propChange.removePropertyChangeListener(listener);
}
我现在将这个 bean 放在另一个名为 TTTBoard 的 bean 中,它给了我以下错误:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at tttboard.TTTCell.addPropertyChangeListener(TTTCell.java:55)
at java.desktop/javax.swing.plaf.synth.SynthPanelUI.installListeners(SynthPanelUI.java:83)
at java.desktop/javax.swing.plaf.synth.SynthPanelUI.installUI(SynthPanelUI.java:63)
at java.desktop/javax.swing.JComponent.setUI(JComponent.java:685)
at java.desktop/javax.swing.JPanel.setUI(JPanel.java:150)
at java.desktop/javax.swing.JPanel.updateUI(JPanel.java:126)
at java.desktop/javax.swing.JPanel.<init>(JPanel.java:86)
at java.desktop/javax.swing.JPanel.<init>(JPanel.java:109)
at java.desktop/javax.swing.JPanel.<init>(JPanel.java:117)
at tttboard.TTTCell.<init>(TTTCell.java:38)
at tttboard.TTTBoard.initComponents(TTTBoard.java:89)
at tttboard.TTTBoard.<init>(TTTBoard.java:27)
at tttboard.TTTBoard.run(TTTBoard.java:203)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
at java.desktop/java.awt.EventQueue.run(EventQueue.java:721)
at java.desktop/java.awt.EventQueue.run(EventQueue.java:715)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
对我来说这没有任何意义 - PropertyChangeSupport 变量已实例化,为什么它应该是空指针?
仅供参考,我使用的是 Netbeans IDE 11.1 和 openjdk 11.0.11
class 的非静态字段在 class 进入其 initialization/construction 之前不会初始化。 Superclass 施工总是先进行。
如果查看堆栈跟踪,您会发现异常是由于 superclass 构造而发生的:
at java.desktop/javax.swing.JPanel.<init>(JPanel.java:117)
at tttboard.TTTCell.<init>(TTTCell.java:38)
在 TTTCell 字段初始化和构造函数可以 运行 之前,superclass 构造函数(即 JPanel 构造函数)必须完成。
JPanel 构造函数调用其 updateUI 方法,最终调用 addPropertyChangeListener:
at tttboard.TTTCell.addPropertyChangeListener(TTTCell.java:55)
at java.desktop/javax.swing.plaf.synth.SynthPanelUI.installListeners(SynthPanelUI.java:83)
at java.desktop/javax.swing.plaf.synth.SynthPanelUI.installUI(SynthPanelUI.java:63)
at java.desktop/javax.swing.JComponent.setUI(JComponent.java:685)
at java.desktop/javax.swing.JPanel.setUI(JPanel.java:150)
at java.desktop/javax.swing.JPanel.updateUI(JPanel.java:126)
at java.desktop/javax.swing.JPanel.<init>(JPanel.java:86)
但是 TTTCell 还没有机会 运行 它的初始化器,它不仅包括 TTTCell()
构造函数,还包括字段的初始化,包括这个:
private PropertyChangeSupport propChange = new PropertyChangeSupport(this);
由于在调用 addPropertyChangeListener 重写时该行尚未 运行(因为 JPanel 构造函数仍未完成),因此 propChange
仍为空。
解决方案很简单:删除对 addPropertyChangeListener 和 removePropertyChangeListener 的覆盖。它们不提供任何好处。组件 class 已经提供了每个方法的有效实现。没有什么能阻止您使用它们。
我刚开始使用 Netbeans 和 PropertyChangeListeners,在 Java bean 中实现 PropertyChangeSupport 时,我遇到了同样(对我来说)奇怪的行为。
所以我有一个名为 TTTCell 的 bean,我在其中初始化了一个 PropertyChangeSupport 变量。然后我实现了维护 属性 更改侦听器列表的功能。
package tttboard;
import java.awt.Color;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
import java.beans.VetoableChangeSupport;
public class TTTCell extends javax.swing.JPanel {
public static enum State
{
INITIAL,
PLAYER_X,
PLAYER_O,
WON,
DISABLE
}
// Variables
private State state;
private PropertyChangeSupport propChange = new PropertyChangeSupport(this);
public TTTCell() {
initComponents();
state = State.INITIAL;
}
@Override
public void addPropertyChangeListener(PropertyChangeListener listener) {
propChange.addPropertyChangeListener(listener); // it depends on that line whether the erroroccurs or not
}
@Override
public void removePropertyChangeListener(PropertyChangeListener listener) {
propChange.removePropertyChangeListener(listener);
}
我现在将这个 bean 放在另一个名为 TTTBoard 的 bean 中,它给了我以下错误:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at tttboard.TTTCell.addPropertyChangeListener(TTTCell.java:55)
at java.desktop/javax.swing.plaf.synth.SynthPanelUI.installListeners(SynthPanelUI.java:83)
at java.desktop/javax.swing.plaf.synth.SynthPanelUI.installUI(SynthPanelUI.java:63)
at java.desktop/javax.swing.JComponent.setUI(JComponent.java:685)
at java.desktop/javax.swing.JPanel.setUI(JPanel.java:150)
at java.desktop/javax.swing.JPanel.updateUI(JPanel.java:126)
at java.desktop/javax.swing.JPanel.<init>(JPanel.java:86)
at java.desktop/javax.swing.JPanel.<init>(JPanel.java:109)
at java.desktop/javax.swing.JPanel.<init>(JPanel.java:117)
at tttboard.TTTCell.<init>(TTTCell.java:38)
at tttboard.TTTBoard.initComponents(TTTBoard.java:89)
at tttboard.TTTBoard.<init>(TTTBoard.java:27)
at tttboard.TTTBoard.run(TTTBoard.java:203)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
at java.desktop/java.awt.EventQueue.run(EventQueue.java:721)
at java.desktop/java.awt.EventQueue.run(EventQueue.java:715)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
对我来说这没有任何意义 - PropertyChangeSupport 变量已实例化,为什么它应该是空指针?
仅供参考,我使用的是 Netbeans IDE 11.1 和 openjdk 11.0.11
class 的非静态字段在 class 进入其 initialization/construction 之前不会初始化。 Superclass 施工总是先进行。
如果查看堆栈跟踪,您会发现异常是由于 superclass 构造而发生的:
at java.desktop/javax.swing.JPanel.<init>(JPanel.java:117)
at tttboard.TTTCell.<init>(TTTCell.java:38)
在 TTTCell 字段初始化和构造函数可以 运行 之前,superclass 构造函数(即 JPanel 构造函数)必须完成。
JPanel 构造函数调用其 updateUI 方法,最终调用 addPropertyChangeListener:
at tttboard.TTTCell.addPropertyChangeListener(TTTCell.java:55)
at java.desktop/javax.swing.plaf.synth.SynthPanelUI.installListeners(SynthPanelUI.java:83)
at java.desktop/javax.swing.plaf.synth.SynthPanelUI.installUI(SynthPanelUI.java:63)
at java.desktop/javax.swing.JComponent.setUI(JComponent.java:685)
at java.desktop/javax.swing.JPanel.setUI(JPanel.java:150)
at java.desktop/javax.swing.JPanel.updateUI(JPanel.java:126)
at java.desktop/javax.swing.JPanel.<init>(JPanel.java:86)
但是 TTTCell 还没有机会 运行 它的初始化器,它不仅包括 TTTCell()
构造函数,还包括字段的初始化,包括这个:
private PropertyChangeSupport propChange = new PropertyChangeSupport(this);
由于在调用 addPropertyChangeListener 重写时该行尚未 运行(因为 JPanel 构造函数仍未完成),因此 propChange
仍为空。
解决方案很简单:删除对 addPropertyChangeListener 和 removePropertyChangeListener 的覆盖。它们不提供任何好处。组件 class 已经提供了每个方法的有效实现。没有什么能阻止您使用它们。