Overloaded constructor calling other constructor, but not as first statement
Solution 1
Typically use another common method - a "construction helper" as you've suggested.
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
}
}
The alternative is a Factory-style approach in which you have a MyClassFactory
that gives you MyClass
instances, and MyClass
has only the one constructor:
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);
}
}
I definitely prefer the first option.
Solution 2
Next possible solution is Factory method. These static methods can be overloaded and after calculation they can call the private / protected constructor
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 );
}
}
EDIT: This method is also ideal when you have a final fields
Solution 3
Although I prefer the factory method option pointed to by several other answers, I wanted to suggest another option: You can use static methods to do the calculation of your other parameters:
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
}
}
Solution 4
The helper and factory options are very good.
There is another one:
public MyClass(int arg1) {
this(arg1, calculateArg2(), calculateArg3());
}
private static int calculateArg2() {..}
private static int calculateArg3() {..}
Solution 5
Use marker values for 'missing'
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);
}
}
For best results, make the 'general' constructor protected
or private
.
David B
Updated on September 08, 2020Comments
-
David B over 3 years
I'm having some trouble using multiple constructors in java.
what I want to do is something like this:
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); } }
but I can't, since the second constructor cannot call another constructor, unless it is the first line.
What is the common solution for such situation? I can't calculate arg2 and arg3 "in line". I thought maybe creating a construction helper method, that will do the actual construction, but I'm not sure that's so "pretty"...
EDIT: Using a helper method is also problematic since some of my fields are final, and I can't set them using a helper method.
-
Jorn over 13 yearsinstead of
return new this(...)
it should bereturn new MyClass(...)
-
Gaim over 13 yearsThis solution is really messy because sometimes you use direct call ( constructor ) and sometimes indirect ( factory method )
-
Matt Mitchell over 13 yearsQuite nice that you can use static methods there.
-
Jorn over 13 yearsI definitely prefer the second option, if you put the factory method in the class itself instead of in a different class. The first option doesn't allow you to make the fields you assign with the parameter values
final
. The compiler can't tell theinit
method is called once in every constructor, and never outside a constructor. If you don't like the factory method, see my answer for another option on calculating other parameters. -
Gaim over 13 yearsSometimes there can be useful to have an option to throw an exception and it is bad habit to throw it from the constructors. For these situations the factory method are better
-
Jorn over 13 yearsI don't like this option, because it doesn't allow you to make the fields you assign with the parameter values final. The compiler can't tell the
init
method is called once in every constructor, and never outside a constructor. -
Jorn over 13 yearsI agree: In this case you should also create a factory method that takes all three arguments, and make the now
public
constructorprivate
instead. -
Bozho over 13 yearsyay for the unexplained downvote. Perhaps you'd dowvote Jorn's answer, which is essentially the same? Or you are Jorn ;)
-
Matt Mitchell over 13 years@Jorn I'm with Steve Yegge on factories, they've always irked me.
-
Bozho over 13 years@Jorn heh, that was the last assumption, but still probable. +1 to your answer so that things get a bit equal.
-
David B over 13 years+ nice! I like all the creative idea that pop out here.