我知道从构造函数调用可覆盖的方法是个坏主意。但我也看到 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/