重载构造函数调用其他构造函数,但不是作为第一条语句
Posted
技术标签:
【中文标题】重载构造函数调用其他构造函数,但不是作为第一条语句【英文标题】: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。我想也许可以创建一个构造辅助方法,它会进行实际的构造,但我不确定这是否如此“漂亮”......
编辑:使用辅助方法也有问题,因为我的一些字段是最终的,我无法使用辅助方法设置它们。
【问题讨论】:
【参考方案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);
为获得最佳结果,请将“通用”构造函数设为protected
或private
。
【讨论】:
+ 不错!我喜欢这里出现的所有创意。【参考方案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
。以上是关于重载构造函数调用其他构造函数,但不是作为第一条语句的主要内容,如果未能解决你的问题,请参考以下文章