Overloaded constructor calling other constructor, but not as first statement

20,023

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.

Share:
20,023
David B
Author by

David B

Updated on September 08, 2020

Comments

  • David B
    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
    Jorn over 13 years
    instead of return new this(...) it should be return new MyClass(...)
  • Gaim
    Gaim over 13 years
    This solution is really messy because sometimes you use direct call ( constructor ) and sometimes indirect ( factory method )
  • Matt Mitchell
    Matt Mitchell over 13 years
    Quite nice that you can use static methods there.
  • Jorn
    Jorn over 13 years
    I 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 the init 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
    Gaim over 13 years
    Sometimes 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
    Jorn over 13 years
    I 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
    Jorn over 13 years
    I agree: In this case you should also create a factory method that takes all three arguments, and make the now public constructor private instead.
  • Bozho
    Bozho over 13 years
    yay for the unexplained downvote. Perhaps you'd dowvote Jorn's answer, which is essentially the same? Or you are Jorn ;)
  • Matt Mitchell
    Matt Mitchell over 13 years
    @Jorn I'm with Steve Yegge on factories, they've always irked me.
  • Bozho
    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
    David B over 13 years
    + nice! I like all the creative idea that pop out here.