【问题标题】:Overloaded constructor calling other constructor, but not as first statement重载构造函数调用其他构造函数,但不是作为第一条语句
【发布时间】:2011-03-24 02:28:21
【问题描述】:

我在 java 中使用多个构造函数时遇到了一些问题。

我想做的是这样的:

public class MyClass {

 // first constructor
 public MyClass(arg1, arg2, arg3) {
  // do some construction
 }

 // second constructor
 public MyClass(arg1) {
      // do some stuff to calculate arg2 and arg3
      this(arg1, arg2, arg3);
    }
}

但我不能,因为第二个构造函数不能调用另一个构造函数,除非它是第一行。

这种情况的常见解决方案是什么? 我无法“在线”计算 arg2 和 arg3。我想也许可以创建一个构造辅助方法,它会进行实际的构造,但我不确定这是否如此“漂亮”......

编辑:使用辅助方法也有问题,因为我的一些字段是最终的,我无法使用辅助方法设置它们。

【问题讨论】:

    标签: java constructor overloading


    【解决方案1】:

    通常使用另一种常用方法 - 如您所建议的“构造助手”。

    public class MyClass { 
    
        // first constructor 
        public MyClass(arg1, arg2, arg3) { 
          init(arg1, arg2, arg3); 
        } 
    
        // second constructor 
        public MyClass(int arg1) { 
          // do some stuff to calculate arg2 and arg3 
          init(arg1, arg2, arg3); 
        } 
    
        private init(int arg1, int arg2, int arg3) {
          // do some construction 
        }
    } 
    

    另一种方法是工厂风格的方法,其中您有一个MyClassFactory,它为您提供MyClass 实例,而MyClass 只有一个构造函数:

    public class MyClass { 
    
        // constructor 
        public MyClass(arg1, arg2, arg3) { 
          // do some construction 
        } 
    } 
    
    public class MyClassFactory { 
    
        public static MyClass MakeMyClass(arg1, arg2, arg3) { 
          return new MyClass(arg1, arg2, arg3);
        } 
    
        public static MyClass MakeMyClass(arg1) { 
          // do some stuff to calculate arg2 and arg3 
          return new MyClass(arg1, arg2, arg3);
        } 
    } 
    

    我绝对更喜欢第一个选项。

    【讨论】:

    • 有时有一个抛出异常的选项会很有用,而从构造函数中抛出它是一个坏习惯。对于这些情况,工厂方法更好
    • 我绝对更喜欢第二种选择,如果你把工厂方法放在类本身而不是不同的类中。第一个选项不允许您使用参数值final 指定您分配的字段。编译器无法告诉 init 方法在每个构造函数中调用一次,并且永远不会在构造函数之外调用。如果您不喜欢工厂方法,请参阅我的答案以获取有关计算其他参数的另一个选项。
    • @Jorn 我和 Steve Yegge 一起在工厂工作,他们总是惹恼我。
    【解决方案2】:

    下一个可能的解决方案是Factory method。这些静态方法可以重载,计算后可以调用私有/受保护的构造函数

    public class MyClass {
    
        private MyClass( arg1, arg2, arg3 ) {
             // do sth
        }
    
        public static MyClass getInstance( arg1 ) {
             // calculate arg2,3
            return new MyClass( arg1, arg2, arg3 );
        }
    
        public static MyClass getInstance( arg1, arg2, arg3 ) {
            return new MyClass( arg1, arg2, arg3 );
        }
    }
    

    编辑:当您有最终字段时,此方法也很理想

    【讨论】:

      【解决方案3】:

      虽然我更喜欢其他几个答案所指向的工厂方法选项,但我想建议另一种选择:您可以使用静态方法来计算其他参数:

      public class MyClass {
          public MyClass(int arg1, int arg2, int arg3) {
              // do some construction
          }
      
          public MyClass(int arg1) {
            //call to this() must be the first one
            this(arg1, calculateArg2(arg1), calculateArg3());
            //you can do other stuff here
          }
      
          private static int calculateArg2(int arg1) {
            //calc arg2 here
          }
      
          private static int calculateArg3() {
            //calc arg3 here
          }
      }
      

      【讨论】:

        【解决方案4】:

        helper 和 factory 选项都很不错。

        还有一个:

        public MyClass(int arg1) {
            this(arg1, calculateArg2(), calculateArg3());
        }
        
        private static int calculateArg2() {..}
        private static int calculateArg3() {..}
        

        【讨论】:

        • 很高兴你可以在那里使用静态方法。
        • 对无法解释的反对票表示赞同。也许您会否决乔恩的答案,这基本上是一样的?或者你是乔恩 ;)
        • @Jorn heh,这是最后一个假设,但仍有可能。为您的答案 +1,这样事情就变得有点平等了。
        【解决方案5】:

        为“缺失”使用标记值

        public class MyClass {
         public MyClass(arg1, arg2, arg3) {
          // do some stuff to calculate arg2 and arg3 if they are the missing values
          // do some construction
         }
         public MyClass(arg1) {
           this(arg1, null, null);
         }
        }
        

        为获得最佳结果,请将“通用”构造函数设为protectedprivate

        【讨论】:

        • + 不错!我喜欢这里出现的所有创意。
        【解决方案6】:

        另一种方式是这样的:

        public class MyClass {
        
          // first constructor
          public MyClass(arg1, arg2, arg3) {
           // do some construction
           doSomeStuffToArg3Arg3(arg2, arg3)
          }
        
          // second constructor
          public MyClass(int arg1) {
              this(arg1, arg2, arg3);
          }
        
          private void doSomeStuffToArg3Arg3(int arg2, int arg3) {
             // do some stuff to calculate arg2 and arg3
          }
        }
        

        【讨论】:

          【解决方案7】:

          您可以将MyClass(arg1, arg2, arg3) 的代码移动到辅助方法中(将其命名为Init 或其他名称),然后在两个构造函数中调用此方法。

          【讨论】:

          • 我不喜欢这个选项,因为它不允许您使用参数值最终分配的字段。编译器无法告诉 init 方法在每个构造函数中调用一次,并且永远不会在构造函数之外调用。
          【解决方案8】:

          作为给出答案的替代方案,最简单的方法是将参数计算重构为3参数构造函数;

          public class MyClass {
          
              // first constructor
              public MyClass(arg1, arg2, arg3) {
                  if (null == arg2) {
                      // calculate arg2
                  }
                  if (null == arg3) {
                      // calculate arg3
                  }
                  // do some construction
              }
          
              // second constructor
              public MyClass(arg1) {
                  this(arg1, null, null);
              }
          }
          

          【讨论】:

            【解决方案9】:

            您可以创建一个调用构造函数的factory method

            public class MyClass { 
            
                // first constructor 
                public MyClass(arg1, arg2, arg3) { 
                // do some construction
            
                } 
            
                // second constructor as factory method
                public static createMyClassAndDoFunkyStuff(int arg1) { 
                  // do some stuff to calculate arg2 and arg3 
                  return new MyClass(arg1, arg2, arg3); 
                } 
            
            } 
            

            【讨论】:

            • 应该是return new this(...)而不是return new MyClass(...)
            • 这个解决方案真的很乱,因为有时你使用直接调用(构造函数),有时使用间接调用(工厂方法)
            • 我同意:在这种情况下,您还应该创建一个接受所有三个参数的工厂方法,并改为使用 now public 构造函数 private
            猜你喜欢
            • 2013-12-10
            • 1970-01-01
            • 2020-07-12
            • 2017-01-01
            • 2012-12-13
            • 1970-01-01
            • 2018-10-17
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多