我知道从构造函数调用可重写的方法是一个坏主意。但我也看到到处都是用 Swing 完成的,其中代码如下add(new JLabel("Something"));
一直出现在构造函数中。
以 NetBeans IDE 为例。它对构造函数中的可重写调用非常挑剔。然而,当它生成 Swing 代码时,它会将所有这些add()
方法调用到initializeComponents()
方法...然后从构造函数中调用!这是隐藏问题并禁用警告的好方法(NetBeans 没有“从构造函数调用调用可重写方法的私有方法”警告)。但并不是真正解决问题的方法。
这里发生了什么?我已经这样做很多年了,但总是有一种不安的感觉。除了制作额外的内容之外,是否有更好的方法来初始化 Swing 容器init()
方法(并且不要忘记每次都调用它,这有点无聊)?
Example
这是一个非常人为的例子,说明了事情是如何出错的:
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);
}
}
或者,您可以全力以赴,使用依赖项注入容器实例化所有 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");
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)