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



这是仅在继承中为真还是在大多数情况下为真?

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方法,因为如果该类用于继承,则构造函数不能直接或间接调用可重写方法

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

来源。

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

如果您调用一个可以被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
    }
}

NPE的原因可能很难看出是否有更大的继承层次。

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

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

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

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

[更新]

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

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

构造函数构造对象,您应该只调用您知道在"未完全构造状态"下工作的东西。在您的示例中,SetId除了设置值之外什么都不做,所以它很好。但是,如果SetId使用了其他尚未准备好的state/info,那么您可能会遇到问题。

这不是一条戒律,而是一条"小心你所做的"

这可能不是一个好主意。如果您不将该类设为final,也不将setName(…)方法设为private或final,则其他人可以扩展您的类并重写setName(..)方法。构造函数(在基类中)将在扩展类中调用该方法,而不是在实现中调用。没有人知道这个方法能做什么。根据经验:构造函数不应该调用可以被覆盖的方法

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

这就是为什么您可能想要将SetId或MyClass设置为最终或私有。

相关内容

  • 没有找到相关文章

最新更新