Tech & Work

Call a default constructor early, but not often

When you call a constructor from within another constructor, Java requires you to do it on the first line. Learn the logic behind this syntax and see how you can use this() to your advantage.


Q: When calling a constructor from within another constructor, why does this() have to appear on the first line? Is there any technical reasoning behind it?

A: The short the answer to this question is because that’s the rule; the Java language syntax states that this() and super() can be used only on the first line of a constructor. But as you’ll usually find, there’s a logical reason behind this syntax. In this case, it's based on initialization and constructor invocation. Essentially, you always use this() and super() on the first line of a constructor to avoid changes in your code’s execution steps that can overwrite specific values with the undesired defaults of other constructors.

First, a little background on this() and super(). These operators call the current instance’s default constructor. This is a common approach to avoid code duplication within a class. Other constructors defined in the class may also require arguments. You evoke them in the same way, except that you also pass the appropriate parameters. In some cases, some elaborate initialization might need to take place upon instantiation of your class. When a new class instance is created, the body of its constructor is executed after all of its superclasses to ensure that members of the superclasses are accessed after they have been initialized. A subclass can then change the values of the inherited members assuming the superclass has allowed access. The same principle applies to overloading constructors for a class. So, using this() and super() only on the first line of a constructor allows the constructor to share common code, yet also gives you the flexibility to alter those members that are different without risking the loss of your customizations.

To demonstrate how the placement of a this() call can affect the execution steps of creating a new class, let’s walk through a few different approaches to the initialization of a sample class, called Simple, which is a subclass of Object. In the first situation, the class instance is created via the default constructor. This constructor contains no this() call. Such a class would be initialized as shown in Listing A.

The first step in creating an instance of the Simple class is memory allocation for the instance variables of Simple and its superclass, Object. Next, the instance variables in classes Object and Simple are set to their default values: 0 for integers iCount and iLine and null for sStr. The Simple constructor is called with no arguments. Since Simple class does not have a call to this() or super(), the compiler adds a call to the default constructor, super(), which calls the constructor of the class Object. Any instance variables are initialized, the body of Object’s constructor is executed, and the flow of control is returned to Simple class. Next, sStr is assigned the value “Simple test,” and the rest of the body of Simple class constructor is executed, setting instance variables iCount to 2 and iLine to 1. Finally, control is returned to main.

If you change the call to the Simple class to use the constructor that takes an argument, you’ll clearly see why this() needs to be the first item in a constructor. Listing B shows how the CallSimple code would now read.

As in the previous example, when an instance of the Simple class is created, memory is allocated for the instance class and its superclass, instance variables are set to their default values, and then the constructor is called. This time, the constructor with one argument is called. This constructor has a call to this() on the first line, which results in the default constructor being invoked. The default constructor does not have super() or this() on the first line, so the compiler adds a call to super() for the class Object. When control is returned from this super() call, sStr is set to “Simple test,” and the rest of the body of Simple class’s default constructor is executed. Control is then returned to the constructor we called. Its body is executed, overwriting the values assigned by the other constructors of variables they have in common. Figure A shows the execution steps in this case.

Figure A
Execution steps with this() on the first line


Now, let’s suppose there was no limitation on where the this() call occurs within the constructor. Change the constructor of Simple to appear on the second line instead of the first, as follows:
Simple(int iCnt)   {
           iCount = iCnt;
           this();
      }

Figure B shows the new set of execution steps.

Figure B
Execution steps when this() is not on the first line


The value of iSimple.iCount is now 2, not the intended value of 4. Calling this() from anywhere but the first line within a constructor could alter variables after other work has been done. And this basic example assigns a different value to just one member of its class. Imagine how chaotic things would be if a large number of members were dependent on other members. The recursion of calling one constructor from another, either explicitly or implicitly, is confusing on first glance. However, on further examination, it’s clear that the recursion is necessary in order to guarantee that members of superclasses and the class itself are accessed in the correct order. For more detailed information on this topic, see section 12.5 of the Java Language Specification.

Do you have a question?
Need Java help? Builder.com’s technical staff is ready and willing. Send us your Java question, and we'll take a crack at it.

 

Editor's Picks

Free Newsletters, In your Inbox