java - 在构造函数中调用像 Swing 的 add() 这样的可覆盖方法

标签 java swing constructor overriding

我知道从构造函数调用可覆盖的方法是个坏主意。但我也看到 Swing 无处不在,像 add(new JLabel("Something")); 这样的代码一直出现在构造函数中。

以 NetBeans IDE 为例。对构造函数中的可覆盖调用非常挑剔。然而,当它生成 Swing 代码时,它会将所有这些 add() 方法调用放入一个 initializeComponents() 方法...然后从构造函数中调用该方法!隐藏问题和禁用警告的好方法(NetBeans 没有“从构造函数调用可覆盖方法的私有(private)方法”警告)。但并不是真正解决问题的方法。

这里发生了什么?我已经做了很多年了,但总是对此感到不安。除了制作一个额外的 init() 方法(并且每次都不要忘记调用它,这有点无聊)之外,有没有更好的方法来初始化 Swing 容器?

示例

这是一个非常人为的例子,说明事情会如何出错:

public class MyBasePanel extends JPanel {
    public MyBasePanel() {
        initializeComponents();
    }

    private void initializeComponents() {
        // layout setup omitted
        // overridable call
        add(new JLabel("My label"), BorderLayout.CENTER);
    }
}

public class MyDerivedPanel extends MyBasePanel {
    private final List<JLabel> addedLabels = new ArrayList<>();

    @Override
    public void add(Component comp, Object constraints) {
        super.add(comp);
        if (comp instanceof JLabel) {
            JLabel label = (JLabel) comp;
            addedLabels.add(label); // NPE here
        }
    }
}

最佳答案

为避免在构造函数中将 Swing 组件连接在一起,您可以简单地将连接的责任交给另一个对象。例如,您可以将布线职责交给工厂:

public class MyPanelFactory {
    public MyBasePanel myBasePanel() {
        MyBasePanel myBasePanel = new MyBasePanel();
        initMyBasePanel(myBasePanel);
        return myBasePanel;
    }

    public MyDerivedPanel myDerivedPanel() {
        MyDerivedPanel myDerivedPanel = new MyDerivedPanel();
        initMyBasePanel(myDerivedPanel);
        return myDerivedPanel;
    }

    private void initMyBasePanel(MyBasePanel myBasePanel) {
        myBasePanel.add(new JLabel("My label"), BorderLayout.CENTER);
    }
}

或者您可以全力以赴,使用依赖注入(inject)容器实例化所有 Swing 组件,并让容器触发连接。这是 Dagger 的示例:

@Module
public class MyPanelModule {
    static class MyBasePanel extends JPanel {
        private final JLabel myLabel;

        MyBasePanel(JLabel myLabel) {
            this.myLabel = myLabel;
        }

        void initComponents() {
            this.add(myLabel, BorderLayout.CENTER);
        }
    }

    static class MyDerivedPanel extends MyBasePanel {
        private final List<JLabel> addedLabels = new ArrayList<>();

        MyDerivedPanel(JLabel myLabel) {
            super(myLabel);
        }

        @Override
        public void add(Component comp, Object constraints) {
            super.add(comp);
            if (comp instanceof JLabel) {
                JLabel label = (JLabel) comp;
                addedLabels.add(label);
            }
        }
    }

    @Provides MyBasePanel myBasePanel(@Named("myLabel") JLabel myLabel) {
        MyBasePanel myBasePanel = new MyBasePanel(myLabel);
        myBasePanel.initComponents();
        return myBasePanel;
    }

    @Provides MyDerivedPanel myDerivedPanel(@Named("myLabel") JLabel myLabel) {
        MyDerivedPanel myDerivedPanel = new MyDerivedPanel(myLabel);
        myDerivedPanel.initComponents();
        return myDerivedPanel;
    }

    @Provides @Named("myLabel") JLabel myLabel() {
        return new JLabel("My label");
    }
}

关于java - 在构造函数中调用像 Swing 的 add() 这样的可覆盖方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36410183/

相关文章:

java - JFrame - 当 JFrame 最小化时,系统托盘上不显示图标

c++ - 使用 init-methods 来避免使用 new 分配对象——这是糟糕的设计吗?

c++ - 在 C++ 文档教程的这个示例中,为什么指针声明了两次?

java - 排除由 CDI 拦截器调用的特定方法

java - android中两个矩形之间的碰撞检测

java - java 中的 fork 流

java - 如何使文本字段在按钮单击时可见?

java - 自定义绘画和 Z 顺序 : query re painting order

java - JScrollPane 内的 JTable : best height to disable scrollbars

c++ - 为什么不允许复制构造函数按值传递?