假设我扩展了一个类并覆盖了其中的方法。为什么在我的新类构造函数中调用被覆盖的方法是一种不良实践?
假设我扩展了一个类并覆盖了其中的方法。为什么在我的新类构造函数中调用被覆盖的方法是一种不良实践?
在构造函数中避免调用可重写方法的主要原因是它允许子类看到半构造状态的类。这可能或可能不是安全风险,但它是一个等待发生的错误。在此处阅读更多。
因为类的实例可能处于不一致的状态。以下是一个具体的例子。
public class Foo {
private int number;
public Foo() {
number = 42;
multiplyNumber();
}
public void multiplyNumber() {
number = number * 2;
}
public int getNumber() {
return number;
}
}
public class Bar extends Foo {
private int number;
public Bar() {
multiplyNumber();
}
@Override
public void multiplyNumber() {
number = number * 3;
}
}
public class FooBar {
public static void main(String[] args) {
Foo foo = new Foo();
Foo bar = new Bar();
System.out.println("Foo number 1 = " + foo.getNumber()); // Returns 84
System.out.println("Foo number 2 = " + bar.getNumber()); // Returns 42;
}
}
bar
构造函数中的 multiplyNumber()
方法从未被调用,直接跳过。因此,number
属性没有预期的值。
构造函数应该是简单的实体;最好不要在其中放置任何非常复杂的内容。有人可以从您的类继承并更改您在构造函数中依赖的行为。
这意味着您不知道该函数将要做什么。
想象一下,在构造函数中调用一个可重写的方法。你再次创建子类并进行覆盖。第二个子类可以中断第一个子类所依赖的工作,以使其被视为完全初始化,从而使其处于损坏状态。
至于构造函数中的工作,你可以做一些工作,但通常应该是初始化对象所需的类型的工作。
作为最佳实践,尽量避免继承,如果你决定将构造函数工作分成方法,请使用可见性修饰符确保所有工作都保留在正在构建的类中。