views:

139

answers:

9

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.

+3  A: 

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.

Graphain
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
Gaim
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.
Jorn
@Jorn I'm with Steve Yegge on factories, they've always irked me.
Graphain
+7  A: 

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

Gaim
A: 

You can move the code of MyClass(arg1, arg2, arg3) into helper method (name it Init or something else ) and then call this method in both constructors.

DixonD
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
A: 

You could create a factory method which calls the constructor:

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); 
    } 

} 
sleske
instead of `return new this(...)` it should be `return new MyClass(...)`
Jorn
This solution is really messy because sometimes you use direct call ( constructor ) and sometimes indirect ( factory method )
Gaim
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.
Jorn
@Jorn: Thanks, fixed.
sleske
+3  A: 

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() {..}
Bozho
Quite nice that you can use static methods there.
Graphain
yay for the unexplained downvote. Perhaps you'd dowvote Jorn's answer, which is essentially the same? Or you are Jorn ;)
Bozho
It's not me, but thanks for the vote of confidence.
Jorn
@Jorn heh, that was the last assumption, but still probable. +1 to your answer so that things get a bit equal.
Bozho
+3  A: 

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
    }
}
Jorn
+1 nice idea Jorn!
David B
A: 

Another way is this:

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
  }
}
naikus
A: 

As an alternative to the answers given, the simplest way is to refactor the argument calculation to the 3 argument constructor;

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);
    }
}
rsp
+1  A: 

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.

Tassos Bassoukos
+ nice! I like all the creative idea that pop out here.
David B