Java subclass 可以继承和覆盖嵌套的 class 吗?

Java can subclass inherit and override nested class?

这是针对 Java Swing JToolBar 的:

我有自己的工具栏 class,它扩展了 JToolBar,它上面有带有 ActionListeners 的按钮。代码:

class ToolBar extends JToolBar {
    JButton save, reset;

    ToolBar() {
        setFloatable(false);
        setRollover(true);
        makeButtons();
    }

    makeButtons() {
        save = new JButton();
        // Icon and tooltip code
        save.addActionListener(new ButtonListener());
        add(save);

        reset = new JButton();
        // Icon and tooltip code
        reset.addActionListener(new ButtonListener());
        add(reset);

    protected class ButtonListener implements ActionListener {
        public void actionPerformed(ActionEvent event) {
        }
    }

然后我制作了这个的其他一些子class,因为我需要多个框架的多个工具栏,每个工具栏都有不同的 "save" 或 "reset" source/target。为了简单起见,我只给出一个:

class FullToolBar extends ToolBar {

    protected class ButtonListener implements ActionListener {
        public void actionPerformed(ActionEvent event) {
            if (event.getSource() == save) FullInput.save();
            else if (event.getSource() == reset) FullInput.reset();
        }
    }
}

FullInput 是我的 JFrame 之一的名称,工具栏将继续使用它。它具有静态的保存和重置方法,但由于某些原因,当我将 FullToolBar 添加到我的 FullInput 时,按钮不起作用。

我是否误解了嵌套的 classes 可以被继承和覆盖?任何 ideas/comments 或什至建议完全不同的方式来完成我在这里想要完成的事情?基本上,需要一种在具有相同工具栏的不同 frames/classes 上使用保存和重置按钮的方法。

不,您不能像那样覆盖嵌套的 class。有几种方法可以解决这个问题。一种是将可覆盖方法放在主工具栏 class 上,例如:

class ToolBar extends JToolBar {

  makeButtons() {
    save = new JButton();
    // Icon and tooltip code
    save.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent event) {
        saveButtonPressed(event);
      }
    });
  }

  protected void saveButtonPressed(ActionEvent event) {}
}

然后,子class 可以通过覆盖 saveButtonPressed 方法来自定义按下保存按钮时的操作。

Am I misunderstanding that nested classes can be inherited and overriden?

是的。虽然你们的 ButtonListener class 同名,但他们之间没有其他联系。嗯...嵌套 classes 是继承的,但它们不能被覆盖。例如,您可以子 class 继承 class:

class FullToolBar extends ToolBar {
    protected class ButtonListener extends ToolBar.ButtonListener {
                                           ^^^^^^^^^^^^^^^^^^^^^^

虽然这在这里没有用,因为它仍然不会 覆盖 ToolBar.

中对 new ButtonListener() 的调用

还有许多其他方法可以实现此目的。如果你真的想覆盖 ButtonListener class,你可以用调用方法 protected ActionListener createListener() 来替换 new ButtonListener() 的使用,以便在 subclasses 中覆盖,这样他们就可以提供他们想要的任何监听器 class 实现。在这种情况下,这可能会使它过于复杂。

这里比较简单的解决办法是让ToolBar直接实现ActionListener,覆盖subclass:

中的actionPerformed方法
class ToolBar extends JToolBar implements ActionListener {
    ...

    void makeButtons() {
        ...
        save.addActionListener(this);
        ...
    }

    public void actionPerformed(ActionEvent event) {
    }
}

class FullToolBar extends ToolBar {
    @Override
    public void actionPerformed(ActionEvent event) {
        if (event.getSource() == save) FullInput.save();
        else if (event.getSource() == reset) FullInput.reset();
        else super.actionPerformed(event);
    }
}

作为它的一个变体,如果你想防止 actionPerformedToolBar 中成为 public,请改用一个受保护的方法,随意命名,并在子classes。使用 Java 8 的方法引用语法将处理程序方法与按钮连接起来:

class ToolBar extends JToolBar {
    ...

    void makeButtons() {
        ...
        save.addActionListener(this::onButtonClick);
        ...
    }

    protected void onButtonClick(ActionEvent event) {
    }
}

class FullToolBar extends ToolBar {
    @Override
    protected void onButtonClick(ActionEvent event) {
        if (event.getSource() == save) FullInput.save();
        else if (event.getSource() == reset) FullInput.reset();
        else super.onButtonClick(event);
    }
}

另一个想法:您真的需要 ToolBar 为这些按钮设置事件侦听器吗?你可以在 subclass:

class ToolBar extends JToolBar {
    ...

    protected void makeButtons() {
        save = new JButton();
        add(save);
        reset = new JButton();
        add(reset);
    }
}

class FullToolBar extends ToolBar {
    @Override
    protected void makeButtons() {
        super.makeButtons();
        save.addActionListener((ActionEvent e) -> FullInput.save());
        reset.addActionListener((ActionEvent e) -> FullInput.reset());
    }
}