Java 将侦听器分配给类时出现问题

Java 将侦听器分配给类时出现问题,java,swing,inheritance,nullpointerexception,listener,Java,Swing,Inheritance,Nullpointerexception,Listener,我的问题在于莫名其妙地不能听我的课 该软件是一个基于java swing的桌面应用程序,JFrame的子类MainFrame正在侦听多个对话框。所有对话框窗口都是my PDialog类的子类,该类包含与侦听器相关的变量和函数。这是PDialog类的外观: public class PDialog extends JDialog { private MainFrameChildrenListener listener; // Function that assigns its paramete

我的问题在于莫名其妙地不能听我的课

该软件是一个基于java swing的桌面应用程序,JFrame的子类MainFrame正在侦听多个对话框。所有对话框窗口都是my PDialog类的子类,该类包含与侦听器相关的变量和函数。这是PDialog类的外观:

public class PDialog extends JDialog {

private MainFrameChildrenListener listener;

// Function that assigns its parameter to local listener value "listener setter"
public void addMainFrameChildrenListener(MainFrameChildrenListener listener) {
    this.listener = listener;
}

public void removeMainFrameChildrenListener() {
    this.listener = null;
}

public void firePDialogEvent(MainFrameChildrenEventObject event) {
    this.listener.dialogEventOccured(event);
}

// This method was useful when I tried to debug with System.out.println() method
public String retrieveListenerInformation(){
    if(listener == null){
        return "No listener loaded";
    }
    return this.listener.toString();
}
}
Material dialog: No listener loaded
Customer dialog: view.MainFrame[-deleted the .toString() rubbish to keep things short-]
Order dialog: view.MainFrame[-deleted the .toString() rubbish to keep things short-]
Product dialog: view.MainFrame[-deleted the .toString() rubbish to keep things short-]
因此,我创建了3个对话框,使用它们作为PDialog的子类继承的函数成功地侦听它们。MainFrame类实现MainFrameChildrenListener侦听器对象,并将其作为侦听器传递给其构造函数中的对话框:

public class MainFrame extends JFrame implements MainFrameChildrenListener {

private PDialogCustomer dialogCustomer = new PDialogCustomer();
private PDialogOrder dialogOrder = new PDialogOrder();
private PDialogProduct dialogProduct = new PDialogProduct();
private PDialogMaterial dialogMaterial = new PDialogMaterial();

public MainFrame(){
    dialogMaterial.addMainFrameChildrenListener(this);
    dialogCustomer.addMainFrameChildrenListener(this);
    dialogOrder.addMainFrameChildrenListener(this);
    dialogProduct.addMainFrameChildrenListener(this);


    System.out.println("Material dialog: " + dialogMaterial.retrieveListenerInformation());
    System.out.println("Customer dialog: " + dialogCustomer.retrieveListenerInformation());
    System.out.println("Order dialog: " + dialogOrder.retrieveListenerInformation());
    System.out.println("Product dialog: " + dialogProduct.retrieveListenerInformation());
}
令人惊讶的是,在应用程序启动后,控制台输出PDialog.retrieveListenerInformation()指令,它看起来是这样的:

public class PDialog extends JDialog {

private MainFrameChildrenListener listener;

// Function that assigns its parameter to local listener value "listener setter"
public void addMainFrameChildrenListener(MainFrameChildrenListener listener) {
    this.listener = listener;
}

public void removeMainFrameChildrenListener() {
    this.listener = null;
}

public void firePDialogEvent(MainFrameChildrenEventObject event) {
    this.listener.dialogEventOccured(event);
}

// This method was useful when I tried to debug with System.out.println() method
public String retrieveListenerInformation(){
    if(listener == null){
        return "No listener loaded";
    }
    return this.listener.toString();
}
}
Material dialog: No listener loaded
Customer dialog: view.MainFrame[-deleted the .toString() rubbish to keep things short-]
Order dialog: view.MainFrame[-deleted the .toString() rubbish to keep things short-]
Product dialog: view.MainFrame[-deleted the .toString() rubbish to keep things short-]
如果我试图触发侦听器事件,则PDialog.FireDialogEvent()方法会出现空指针异常。 我曾试图通过其构造函数将侦听器传递给PDialogMaterial类,我甚至试图仅在PDialogMaterial类中创建新方法来传递侦听器,但没有成功。我能够使事情正常运行的唯一方法是创建新的MainFrameChildrenListener变量,该变量声明为public(eek!),并从大型机构造函数直接访问它,如下所示:

public class PDialogMaterial extends PDialog{
public MainFrameChildrenListener testListener;
}

public class MainFrame extends JFrame implements MainFrameChildrenListener{
  public MainFrame(){
    dialogMaterial.testListener = this;
    dialogCustomer.addMainFrameChildrenListener(this);
    dialogOrder.addMainFrameChildrenListener(this);
    dialogProduct.addMainFrameChildrenListener(this);

  }
}
有没有解释为什么四个类中有三个继承了相同的侦听器处理方法,它们的行为与第四个类不同?我会错过什么

意见跟进:

PDialogMaterial(不工作)的完整代码:


这个令人不快的类的问题是它重新声明了

private MainFrameChildrenListener listener;

场。因此有两个私有字段,一个在超类中,一个在子类中,名称相同。当您在子类的方法中时,子类中的一个会覆盖超类中的一个,但对于在超类中定义的方法不可见。删除子类中的listener字段,它应该可以工作。

有问题的类中的问题是它重新声明了

private MainFrameChildrenListener listener;
场。因此有两个私有字段,一个在超类中,一个在子类中,名称相同。当您在子类的方法中时,子类中的一个会覆盖超类中的一个,但对于在超类中定义的方法不可见。删除子类中的listener字段,它应该可以工作。

如前所述,在不工作的listener中,您正在隐藏listener字段并重新声明setter

为了说明这个问题,我建立了一个小例子:

import java.util.Arrays;

public class HiddenField {

    static abstract class Base {
        String field = "BASE";

        // sets the base's field
        void setField(String set) {
            this.field = set;
        }

        // ensures not to be overridden and returns the base's field.
        final String getField() {
            return this.field;
        }

        // access the field by getter (ensured to be base) and field 'field'
        @Override
        public String toString() {
            return this.getClass().getSimpleName() + ": get()->" + getField() + " vs. field->" + field;
        }
    }

    static class ProperExtension extends Base {
        /* no need to override the base's field */
    }

    static class HidingExtension extends Base {

        // this field isn't related to the one in Base, but has the same name!
        String field = "HIDING";

        // the setter is overridden (exact copy!) but because of the same-named
        // field in this extending class, it sets this class's field and not the
        // one in the base-class!
        @Override
        void setField(String set) {
            this.field = set;
        }

        // copied the toString from above - here it is accessing the
        // base-class's field via getter and this class's field directly.
        @Override
        public String toString() {
            return this.getClass().getSimpleName() + ": get()->" + getField() + " vs. field->" + field;
        }
    }

    public static void main(String[] args) {
        // build both types of extending classes and invoke their setters
        Arrays.asList(new ProperExtension(), new HidingExtension()).forEach(obj -> {
            System.out.println("before ~> " + obj);
            obj.setField("SET");
            System.out.println("after  ~> " + obj + "\n");
        });
    }
}
如前所述,在不工作的侦听器中,您正在隐藏侦听器字段并重新声明setter

为了说明这个问题,我建立了一个小例子:

import java.util.Arrays;

public class HiddenField {

    static abstract class Base {
        String field = "BASE";

        // sets the base's field
        void setField(String set) {
            this.field = set;
        }

        // ensures not to be overridden and returns the base's field.
        final String getField() {
            return this.field;
        }

        // access the field by getter (ensured to be base) and field 'field'
        @Override
        public String toString() {
            return this.getClass().getSimpleName() + ": get()->" + getField() + " vs. field->" + field;
        }
    }

    static class ProperExtension extends Base {
        /* no need to override the base's field */
    }

    static class HidingExtension extends Base {

        // this field isn't related to the one in Base, but has the same name!
        String field = "HIDING";

        // the setter is overridden (exact copy!) but because of the same-named
        // field in this extending class, it sets this class's field and not the
        // one in the base-class!
        @Override
        void setField(String set) {
            this.field = set;
        }

        // copied the toString from above - here it is accessing the
        // base-class's field via getter and this class's field directly.
        @Override
        public String toString() {
            return this.getClass().getSimpleName() + ": get()->" + getField() + " vs. field->" + field;
        }
    }

    public static void main(String[] args) {
        // build both types of extending classes and invoke their setters
        Arrays.asList(new ProperExtension(), new HidingExtension()).forEach(obj -> {
            System.out.println("before ~> " + obj);
            obj.setField("SET");
            System.out.println("after  ~> " + obj + "\n");
        });
    }
}

1) 为了更快地获得更好的帮助,请发布一个or。2) 请参阅并发布
PDialogMaterial
的代码,以及其他类似
PDialogOrder
@andreThompson的代码。我已跟踪堆栈跟踪并找到抛出空指针的方法。它并没有让我更接近解决方案,因为其他类使用这个方法没有任何问题。经过简化课程的从头开始,我再也没有例外。我正在研究最小、完整和可验证的示例,但可能需要一段时间:(您需要模型和控制器部分吗?…您需要模型和控制器部分吗?“我们需要一份属于VE的MC。阅读链接并询问任何您不理解的内容。鉴于我是SSCCE的作者,以及MCVE的初稿,我完全有能力解释。可能是1)的副本,为了更快地获得更好的帮助,请发布一份或多份。2) 请参阅并发布
PDialogMaterial
的代码,以及其他类似
PDialogOrder
@andreThompson的代码。我已跟踪堆栈跟踪并找到抛出空指针的方法。它并没有让我更接近解决方案,因为其他类使用这个方法没有任何问题。经过简化课程的从头开始,我再也没有例外。我正在研究最小、完整和可验证的示例,但可能需要一段时间:(您需要模型和控制器部分吗?…您需要模型和控制器部分吗?“我们需要的是一个虚拟现实的MC。阅读链接并询问您不了解的任何内容。鉴于我是SSCCE的作者,以及MCVE的初稿,我可以很好地进行解释。可能是重复的谢谢!感谢您的努力和您花时间浏览我的意大利面软件!它成功了,现在我终于可以继续了谢谢你!谢谢你的努力和你花的时间来使用我的意大利面软件!它成功了,现在我终于可以继续了。