为什么从构造函数调用Set方法不是一个好主意?

仅在inheritance或大多数情况下是真的吗?

public class MyClass { public int id; public MyClass() { // Some stuff setId(5); } public setId(int id) { this.id = id; } } 

这是真的。

因为setter总是public方法。 如果你的课不是final那么就有外星人方法调用的问题。 这不是线程安全的,即它被称为逃避this引用。 所以从构造函数中,如果你调用一个方法,它应该是finalprivate 。 否则不会发生对象的safe initialization ,这会导致实际系统中的许多错误。

除了上面的内容之外,我们永远不应该从constructor调用public方法,因为如果该类用于inheritance,那么构造函数不能直接或间接地调用可覆盖的方法

如果违反此规则,将导致程序失败。 超类构造函数在子类构造函数之前运行,因此在子类构造函数运行之前将调用子类中的重写方法。 如果重写方法依赖于子类构造函数执行的任何初始化,则该方法将不会按预期运行。

来源 。

您不应该从构造函数中调用可覆盖的方法。

如果调用一个可以被costructor中的子类覆盖的方法,那么子类可能会访问尚未初始化的超类的变量。

例如,以下代码到目前为止看起来很好

 class MyClass { public int id; protected String someStr; public MyClass() { SetId(5); someStr = "test"; } public void SetId(int Id) { id = Id; } } 

如果你现在是MyClass子类并重写了SetId方法,你可能会访问尚未初始化的超类的someStr变量,因此在这种情况下会导致NullPointerException

 class MySubClass extends MyClass { public void SetId(int Id) { id = Id; someStr.toString(); // will cause NullPointerException } } 

如果有更大的inheritance层次结构,可能很难看出NPE的原因。

如果它只是你想要的setter方法,那么从构造函数本身初始化你的变量。

 public class MyClass { int id; public MyClass() { id=5; } } 

否则,您可以调用私有/最终方法来遵守OOP理论。

请记住,只有在构造函数中执行最后一个语句或退出构造函数后才能完成对象初始化。

[更新]

这里发生了类似的,更有趣的讨论

Java – Subclass调用超级构造函数,它调用子类方法而不是自己的方法

构造函数构造对象,您应该只调用您知道在“未完全构造的状态”中工作的东西。 在你的例子中,SetId没有做任何其他设置值的事情,所以没关系。 但是,如果SetId使用了尚未准备好的其他状态/信息,那么您可能会遇到问题。

这不是一条诫命 – 而是“对你做的事情保持警惕”

这可能不是一个好主意。 如果你没有使该类成为final,并且不使setName(…)方法成为私有或最终的,那么其他人就可以扩展你的类并覆盖setName(…)方法。 您的构造函数(在您的基类中)将在扩展类而不是您的实现中调用该方法。 没有人知道该方法可以做什么。 根据经验:构造函数不应该调用可以覆盖的方法

因为在Java中,默认情况下所有函数都是虚函数,所以ctor中未启封的方法调用存在风险,原因在于此线程中解释的原因。

这就是为什么你可能想要将SetId或MyClass设为final或private。