Chapter 3 |
Constructor
The initialization shown in the last example is not efficient. Though, we did not have to make up numerous unique variable names (e.g. liza_name, liza_breed, liza_age, marfa_name, etc.) due to dot notation, the number of lines has not been reduced :) Furthermore, such initialization does not avoid situations when one or more fields of an instance are not defined by chance.
The situation can be improved by creating objects in the client class using a constructor that initializes the instance fields:
Dog liza = new Dog("Liza", "labrador", 3, "small", "brown"); Dog marfa = new Dog("Marfa", "beagle", 5, "small", "yellow-white-black");
Variables liza and marfa are ordinary variables, but the data type is Dog (not String or anything else). Furthermore, the right hand side of the declaration looks a bit like a method call with arguments. This is because the keyword new calls a special method - a constructor.
A constructor is a special type of methods that is invoked by the operator new
. Constructors create and initialize objects.
Let us explain the term of constructor in detail.
If we call a special method in the client class, the method should be defined somewhere. The constructor is always defined in the object class after the instance fields. A general syntax for a constructor header:
public ClassName(list_of_parameters) {
Unlike typical methods, in the constructor header:
- the name of the method is the class name (e.g. Dog);
- there is no return type because a constructor always returns an object of its own class.
The constructor is called when a new object is being created. If we want the user to be able to specify the object state (instance fields), the constructor must have parameters that match the instance fields:
// a constructor for class Dog: public Dog(String dogName, int dogAge, String dogColor) { name = dogName; breed = "labrador"; age = dogAge; size = "small"; color = dogColor; }
Notice: this constructor accepts values for three fields from the client class; the other two fields are set to the default values inside the constructor.
In the last example, we used different names for the parameters (e.g. dogName) than the instance fields (e.g. name), but since the parameters and the instance fields store the same type of data, it is preferable to use the same names and the keyword this
:
public Dog(String name, int age, String color) { this.name = name; breed = "labrador"; this.age = age; size = "small"; this.color = color; }
Java can distinguish the instance fields from the method parameters using the keyword this
. If we remove the keyword this
, an instance field and a method parameter will have identical names - as a result, the field will not be assigned its value; however, the method parameters will uselessly set themselves to their own values. Oops!
Default constructors
Frankly speaking, we do not have to provide a constructor for an object class at all. If there are no constructors in the object class, Java provides a default constructor known as the zero argument constructor.
Remind the example from the last page. We managed to create an object without any implicit constructors - simply using statement Dog liza = new Dog();
.
In such case, the default constructor looks like this:
public Dog() { }
In such case, the fields are assigned the default values (like null for Strings or other objects, or 0 for integers, or 0.0 for doubles).
Can we create our own zero argument constructor? Yes, sure.
public Dog() { this.name = "No name"; this.breed = "Unknown"; this.age = 0; this.size = "Unknown"; this.color = "Unknown"; }
In this zero argument constructor, we set the default values to No name, Unknown or 0.
Overloading constructors
Just like method overloading, constructors can also be overloaded (an object class can have several constructors all with the same name). This allows users to decide what amount of data should be specified by default and what amount of data should be given as arguments when an object is created.
To overload constructors, use different signatures (check the number of formal parameters and their data types). We recommend to create a constructor that initializes all fields inside the constructor at first:
public class Dog{ // Instance fields String name; String breed; int age; String size; String color; // Constructor public Dog (String name, String breed, int age, String size, String color) { this.name = name; this.breed = breed; this.age = age; this.size = size; this.color = color; } }
In this example, we have moved all field declarations within the constructor, giving the user a complete control over the initial state of an object. Next, we can add other constructors that include default values (so that the user does not have to specify everything) or call the most specific constructor from the less specific constructors - the later means that we can call one constructor from other constructor using keyword this
in the place where a method name would normally be:
public class Dog{ // Instance fields String name; String breed; int age; String size; String color; // The most specific constructor public Dog (String name, String breed, int age, String size, String color) { this.name = name; this.breed = breed; this.age = age; this.size = size; this.color = color; } // The less specific constructors public Dog() { this("No name","Unknown",0,"Unknown","Unknown"); } }
Which one of the constructors will be used for the object initialization depends on the number of arguments and their data types:
// call the default constructor without parameters Dog liza = new Dog(); // call the most specific constructor Dog liza = new Dog("Liza", "labrador", 3, "small", "brown");
Last but not least, we can also create a constructor in a fast way using IntelliJ: from the Code menu choose Generate.
Chapter 3 |