构造函数中可覆盖的方法调用有什么问题?

问题:

我有一个Wicket页面类,根据抽象方法的结果设置页面标题。

public abstract class BasicPage extends WebPage {

    public BasicPage() {
        add(new Label("title", getTitle()));
    }

    protected abstract String getTitle();

}

NetBeans使用消息“构造函数中的可覆盖方法调用”来警告我,但是应该怎么办?我可以想象的唯一的替代方法是将否则抽象方法的结果传递给子类中的超构造函数。但是很多参数可能很难阅读。

回答:

从构造函数调用可覆盖的方法

简单地说,这是错误的,因为它不必要地开辟了MANY错误的可能性。当调用@Override时,对象的状态可能不一致和/或不完整。
来自Effective Java 2nd Edition, Item 17: Design and document for inheritance, or else prohibit it的报价

课程必须遵守允许继承的更多限制。 构造函数不能调用可覆盖的方法,直接或间接。如果您违反此规则,将导致程序故障。超类构造函数在子类构造函数之前运行,因此子类中的重写方法将在子类构造函数运行之前被调用。如果重写方法取决于子类构造函数执行的任何初始化,该方法将不会按预期方式运行。

下面是一个例子来说明:

public class ConstructorCallsOverride {
    public static void main(String[] args) {
        abstract class Base {
            Base() { overrideMe(); }
            abstract void overrideMe(); 
        }
        class Child extends Base {
            final int x;
            Child(int x) { this.x = x; }
            @Override void overrideMe() {
                System.out.println(x);
            }
        }
        new Child(42); // prints "0"
    }
}

这里,当Base构造函数调用overrideMeChild尚未完成初始化final int x,并且该方法获取错误的值。这几乎肯定会导致错误和错误。

相关问题

也可以看看

对象构造具有很多参数

具有许多参数的构造函数可能导致较差的可读性,并且存在更好的替代方案。
这是Effective Java 2nd Edition, Item 2: Consider a builder pattern when faced with many constructor parameters的报价

传统上,程序员已经使用了telescoping constructor模式,其中只提供一个构造函数只需要所需的参数,另一个可以使用一个可选参数,另外一个可以使用两个可选参数,等等…

伸缩构造器模式基本上是这样的:

public class Telescope {
    final String name;
    final int levels;
    final boolean isAdjustable;

    public Telescope(String name) {
        this(name, 5);
    }
    public Telescope(String name, int levels) {
        this(name, levels, false);
    }
    public Telescope(String name, int levels, boolean isAdjustable) {       
        this.name = name;
        this.levels = levels;
        this.isAdjustable = isAdjustable;
    }
}

现在您可以执行以下任何操作:

new Telescope("X/1999");
new Telescope("X/1999", 13);
new Telescope("X/1999", 13, true);

但是,您目前不能仅设置nameisAdjustable,而将levels设置为默认值。你可以提供更多的构造函数重载,但是显然这个数字会随着参数数量的增加而爆炸,甚至可能有多个booleanint参数,这真的会让事情变得混乱。
正如你所看到的,这不是一个愉快的写作模式,甚至不太适合使用(“真实”是什么意思,什么是13?)。
Bloch建议使用构建器模式,这样可以让你写这样的东西:

Telescope telly = new Telescope.Builder("X/1999").setAdjustable(true).build();

请注意,现在,这些参数是命名的,您可以按照所需的任何顺序进行设置,您可以跳过要保留的默认值。这肯定比伸缩构造函数好多了,特别是当有大量参数属于许多相同的类型时。

也可以看看

相关问题

 
 
Code问答: http://codewenda.com/topics/python/
Stackoverflow: What’s wrong with overridable method calls in constructors?

*转载请注明本文链接以及stackoverflow的英文链接

发表评论

电子邮件地址不会被公开。 必填项已用*标注

− 3 = 7