【问题标题】:Why it is not a good idea to call Set method from constructor?为什么从构造函数调用 Set 方法不是一个好主意?
【发布时间】:2013-11-21 09:10:19
【问题描述】:

是只在继承还是大多数情况下才成立?

public class MyClass {
   public int id;

     public MyClass() {
         // Some stuff 
         setId(5);
     }

     public setId(int id) {
         this.id = id;
     }
}

【问题讨论】:

    标签: java inheritance


    【解决方案1】:

    这是非常真实的。

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

    除此之外,我们永远不应该从constructor 调用public 方法,因为如果该类旨在用于继承,则构造函数不得直接或间接调用可覆盖的方法

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

    source.

    【讨论】:

    • 请注意,有时需要从构造函数调用子类方法。虽然有人想通过抽象类或其他东西来强调这一点......
    • @StackOverflowException,不是一个好主意。详情见我的回答。
    • @StackOverflowException 这是一个糟糕的设计。
    • @Trying:我写了sometimes,我应该写rarely。在某些情况下,如果记录得当,这可以提供更好的解决方案。
    • 如果类不是 final 是什么意思?
    【解决方案2】:

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

    如果您在协构函数中调用可以被子类覆盖的方法,则子类可能会访问尚未初始化的超类的变量。

    例如,到目前为止,以下代码看起来不错

    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 的原因可能很难看出是否存在更大的继承层次结构。

    【讨论】:

      【解决方案3】:

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

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

      否则,您可以调用私有/最终方法以符合 OOP 理论。

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

      [更新]

      这里正在进行类似的、更有趣的讨论

      Java - Subclass calls supers constructor which calls subclass method instead of its own

      【讨论】:

        【解决方案4】:

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

        这不是一条诫命——而是“小心你所做的事情”

        【讨论】:

          【解决方案5】:

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

          【讨论】:

            【解决方案6】:

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

            这就是您可能希望将 SetId 或 MyClass final 设为私有的原因。

            【讨论】:

            • ctor 是一个外来词。是构造函数吗!
            猜你喜欢
            • 2011-01-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-08-23
            • 2012-09-16
            • 2012-04-29
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多