1

Just started learning java recently, and in my textbook I came across this which was very confusing at first but now its starting to make sense. Now, in my book we started basic applications of constructors and as a side note on the page it said this, can also be used to call other constructors. I was a bit confused, then look at other questions on SO regarding this. I think I get it to an extent now, but WHY would I ever want to do this? Consider the following which I just made up.

private double balance;
private double interest;
public Account(double initialBalance){
    balance = initialBalance;

}
public Account(double balance, double interest){
    this(0);
    balance = initialBalance;
    this.interest = interest;
}

Here this(0);, to my understanding looks for another constructor with one parameter, finds Account(double initialBalance), and sets initialBalance to zero. Great. Erm, but why wouldn't I just do that directly? Just set balance equal to zero! I am sure it is very useful but I can't think of any examples. Thanks!

Muntasir Alam
  • 1,777
  • 2
  • 17
  • 26
  • whether you write it like that or not, you always are. the first statement from a(ny) constructor, is to call a/the constructor of the parent class – Stultuske Jul 20 '16 at 14:02
  • 2
    @Stultuske This has nothing to do with the parent class. No pun intended. – Zircon Jul 20 '16 at 14:03
  • @Zircon: call another constructor ... which is basically what I described. if it's from within the same class, the code he posted is either not the code from his book, or they used it as an example of what not to do, or it's a crappy book. – Stultuske Jul 20 '16 at 14:06
  • Sure, if all you're doing in the constructor is simple assignment it doesn't make much difference, but what if you constructor is more complicated (e.g. parameter validation)? You wouldn't want to have to write the same code in multiple constructors. – azurefrog Jul 20 '16 at 14:07
  • 1
    See this post : http://stackoverflow.com/questions/18444198/advantages-of-constructor-overloading – Unknown Jul 20 '16 at 14:08
  • You could replace ` this(0)` with `balance =0`. Would you also do it if `Account(double initialBalance)` had 30 code lines ? See http://codethataint.com/blog/telescoping-constructor-pattern-java/ – c0der Jul 20 '16 at 14:08
  • @Stultuske "Consider the following which I just made up..." and the question is about `this` as a constructor call. You should read questions more carefully before making comments. – Zircon Jul 20 '16 at 14:10
  • @Zircon did you read the question? "Consider the following which I just made up." which means it is not the code he saw in the book, meaning it is not the code he didn't understand, but just something that 'appears to be the same' – Stultuske Jul 21 '16 at 16:13

8 Answers8

5

It's very practical and avoids code duplication:

public Account(){
    this(0);
}

public Account(double initialBalance){
    this(initialBalance, DEFAULT_INTEREST_RATE);
}

public Account(double balance, double interest){
    balance = initialBalance;
    this.interest = interest;
}

The constructors with less arguments delegate to constructors with more arguments, passing defaults for the absent arguments.

If this weren't possible, one would need an artificial init(..) method which accepts the parameters, and is called from all constrcutors. This is less secure, as this method could be called repeatedly.

Peter Walser
  • 15,208
  • 4
  • 51
  • 78
  • Could you expand on one would need an articial init(..), or is that something I will learn later? – Muntasir Alam Jul 20 '16 at 14:25
  • 1
    What @Peter means is that if Java did not allow a constructor to call another constructor, then one way to avoid code duplication in multiple constructors is to just have each of the constructors call a single method that performs the code that would otherwise be duplicated. He happens to name that method "init". This is not secure since that method could also be called elsewhere in the class. – FredK Jul 20 '16 at 14:44
  • exactly what @FredK said ^^ – Peter Walser Jul 21 '16 at 16:02
3

The example from Java documentation will probably make much more sense than the one you have at your hands:

public class Rectangle {
    private int x, y;
    private int width, height;

    public Rectangle() {
        this(0, 0, 1, 1);
    }
    public Rectangle(int width, int height) {
        this(0, 0, width, height);
    }
    public Rectangle(int x, int y, int width, int height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }
    ...
}
κροκς
  • 592
  • 5
  • 18
1

Think about that you could do it the other way: Your "basic" constructor is

public Account(double balance, double interest){
    balance = initialBalance;
    this.interest = interest;
}

and based on this, you could add some simplifications:

public Account(double initialBalance){
    this(initialBalance, DEFAULT_INTEREST);
}

public Account(){
    this(DEFAULT_INITIAL_BALANCE, DEFAULT_INTEREST);
}

Calling these constructors simplifies changing the principal behaviour: if I, e. g., want to register the new object somewhere, I can do so at one central place and have the other constructors rely on that.

glglgl
  • 89,107
  • 13
  • 149
  • 217
1

Here's a good example to use another constructor of the same Object:

public Person(String name, String street, String location) {
   (...)
   //handle them
}

public Person() {
   this("default name", "default street", "default location");
}

It's basically a shortcut (Overloading), so you stay clear of redundant code.

dly
  • 1,080
  • 1
  • 17
  • 23
1

That example does indeed make not much sense.

The following does.

private double balance;
private double interest;

public Account(double initialBalance){
    this(initialBalance, 9.99);
}

public Account(double balance, double interest){
    this.balance = balance;
    this.interest = interest;
}

And indeed one calls another constructor, that typically does some work than just assigning.

For the original example it could be that the simple constructor was made first, and later the constructor with the extra argument was added for an extra field interest.

So one might see this construct often, and it is comparable with calls to super(...)

Also in simple cases, this usage follows the DRY principle: Don't Repeat Yourself. Mind if one of the constructor had just a bit different couple of assignments in time, the program would become constructor case dependent. Now you know, that the same code is walked through, and you do not have to test that functionality N times.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
1

Overloading constructors may come in handy many times. One example is when you have multiple arguments but not all of the are mandatory.

Using overloading you can do something like:

public Account(string id, double balance, string name, strings address){
    this.id = id;
    this.balance = balance;
    this.name = name;
    this.address = address;
}

public Account(string id, double balance, string name){
    this(id, balance, name, null);
}

public Account(string id, double balance){
    this(id, balance, "Unknown" ,null);
}

public Account(string id){
    this(id, 0, "Unknown" ,null);
}
Matan Lachmish
  • 1,235
  • 12
  • 17
0

This is called "constructor overloading". Just like method overloading, this is Java's way of allowing you to supply different amounts of parameters for a single method.

It is generally used for methods, or in this case, constructors that have "optional" parameters. Heres an example that should make it more obvious:

class Cat{
    private int paws;
    private String name;

    public Cat(String name){
        //Assume that the cat is physically not handicapped, and thus has 4 paws
        this(name,4);
    }

    public Cat(String name, int paws){
        this.name = name;
        this.paws = paws;
    }
}
RoyB
  • 3,104
  • 1
  • 16
  • 37
0

It would make more sense if you put it the other way around.

public Account(double initialBalance){
    this(initialBalance, 2.0); // 2.0 being a default interest (whatever you'd like, could be 0).
}

public Account(double balance, double interest){
    this.balance = balance;
    this.interest = interest;
    // Some more very difficult business logic
}

This way you can prevent duplicate code. A change in the difficult business logic would only have to be changed once (if needed).

Robert van der Spek
  • 1,017
  • 3
  • 16
  • 37