Constructors

As we saw in Section 4.4 (Data Creation—Creating Instances), code for creating an instance of game state can be somewhat lengthy and repetitious. A special method called a constructor allows us make each class responsible for its own initialization.

A constructor is called when a new instance of a class is created. A constructor allows you to provide code that should be run in order to prepare an object for use. Your class may have fields that need to be set to default values, or fields that are arrays and so need to be created.

A class's constructor is called when you create a new instance of the class with the new operator. This is true even if you have not declared a constructor for the class. Java provides a default constructor that is called if you do not provide one. That is why we have been able to show examples of using the new operator without having declared constructors.

Suppose you want to set the player scores to zero when you initialize a new instance of the RockPaperScissorsGame class. It's not absolutely necessary to do that with a constructor, but doing so ensures that it happens whenever a new instance is created. Here's an incomplete RockPaperScissorsGame class, but showing a constructor that initializes the new instance's fields to 0:

public class RockPaperScissorsGame {
    int player1Score;
    int player2Score;
    
    public RockPaperScissorsGame() {
        player1Score = 0;
        player2Score = 0;
    }
}

You can see that a constructor looks a lot like a method, but instead of having a return type and its own name, it has no return type, and simply has the name of the class it is within.

A constructor has the following general form:

[ access-modifier ] class-name ( [ parameter [[, parameter ]]] ) {
      body
}

  • access-modifier is public, private, protected, or nothing (for default access);
  • class-name is the name of the class the constructor is within;
  • type is a Java type;
  • parameter is a parameter declaration: parameter-type parameter-name;
  • body is the constructor's code.

When the new operator is invoked, as in this code—

RockPaperScissorsGame rpsState = new RockPaperScissorsGame();

—Java creates an instance of the class, then calls the constructor. When the constructor is finished, new yields the new instance created.

this

Here's an example of a constructor that uses parameters:

public class Distance {
   double value;
   Units units;
    
   public Distance(double val, Units unts) {
      value = val;
      units = unts;
   }
}
    
enum Units { Kilometers, Miles }

The parameter names val and unts are abbreviations for “value” and “units.” If we instead used value and units, the parameters would “hide” the fields, because the fields have the same names.

But it is inconvenient to have to make new names just to avoid the hiding issue. The constructor would be more clear if its parameters had straightforward names, as the fields do. Java provides a mechanism to explicitly refer to the fields (and methods) of an object from within the object's methods and constructors. this, used within a constructor or a non-static method, refers to the object of the method or constructor currently being executed. Now we can write the Distance constructor like this:

   public Distance(double value, Units units) {
      this.value = value;
      this.units = units;
   }

Now we have clear parameter names, and we can refer to the fields so that we can we can copy the parameter values into the fields.

By the way, once you have defined a constructor for a class, the default constructor (which has zero parameters and is called the “no-args” constructor) is no longer available. So this code—Distance d = new Distance();—would fail to compile.

Multiple constructors

You can define as many constructors as you like, as long as each constructor has a different parameter list. This is usually done as a convenience for programmers using your class. For example, you may wish to provide a Distance constructor that requires only one parameter, value. The units would be set to a default, perhaps Kilometers.

   public Distance(double value, Units units) {
      this.value = value;
      this.units = units;
   }
   
   public Distance(double value) {
      this.value = value;
      this.units = Units.Kilometers;
   }

A strong rule in computer programming is to never write identical code. If you find yourself writing code that is nearly identical to other code you have written, then you should try to use that first code if at all possible. If we look at the code above, we can see that the two constructors are nearly identical. With another usage of this, Java lets us call one constructor from another:

   public Distance(double value, Units units) {
      this.value = value;
      this.units = units;
   }
   
   public Distance(double value) {
      this(value, Units.Kilometers); // calls first constructor
   }

You can invoke one constructor from another only if that is the first thing you do in the constructor.