【问题标题】:Adding a PropertyChangeListener leads to java.lang.NullPointerException添加 PropertyChangeListener 会导致 java.lang.NullPointerException
【发布时间】:2022-01-14 13:31:17
【问题描述】:

我是使用 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$2.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$4.run(EventQueue.java:721)
    at java.desktop/java.awt.EventQueue$4.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

【问题讨论】:

    标签: java netbeans nullpointerexception propertychangelistener propertychangesupport


    【解决方案1】:

    一个类的非静态字段在该类进入其初始化/构造之前不会被初始化。超类的构造总是首先发生。

    如果查看堆栈跟踪,可以看到异常是超类构造的结果:

    at java.desktop/javax.swing.JPanel.<init>(JPanel.java:117)
    at tttboard.TTTCell.<init>(TTTCell.java:38)
    

    在 TTTCell 字段初始化和构造函数可以运行之前,超类构造函数(即 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 的覆盖。他们没有提供任何好处。 Component 类已经提供了每个方法的工作实现。没有什么能阻止你使用它们。

    【讨论】:

    • 感谢您的回答!但是,为什么在 PropertyChangeListener 的每个教程中都必须实现这些 Overrides,如果您也可以将它们排除在外而没有任何效果?
    • 编辑:如果我只是删除它们是行不通的——我认为那是因为我的实际变量PropertyChangeSupport propChange 永远不会添加一个监听器。但是,如果我只是在 addPropertyChangeListener 方法中直接初始化 PropertyChangeSupport 变量,它就可以工作。
    • 删除您的 propChange 变量。你不需要它。组件提供firePropertyChange 方法,这些方法将调用任何添加的侦听器。
    猜你喜欢
    • 2015-03-07
    • 1970-01-01
    • 1970-01-01
    • 2019-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-25
    相关资源
    最近更新 更多