Customizing constructors and initialization
We want to initialize instances of the Rectangle
class with the width and height values for the new rectangle. In order to do so, we can take advantage of the previously introduced constructors. Constructors are special class methods that are automatically executed when we create an instance of a given type. Java runs the code within the constructor before any other code within a class.
We can define a constructor that receives both the width and height values as arguments, and use it to initialize the fields with the same names. We can define as many constructors as we want to, and therefore, we can provide many different ways of initializing a class. In this case, we just need one constructor.
The following lines create a Rectangle
class and define a constructor within the class body. At this time, we aren't using access modifiers at all because we want to keep the class declaration as simple as possible. We will work with them later. The code file for the sample is included in the java_9_oop_chapter_03_01
folder, in the example03_03.java
file.
class Rectangle { double width; double height; Rectangle(double width, double height) { System.out.printf("Initializing a new Rectangle instance\n"); System.out.printf("Width: %.2f, Height: %.2f\n", width, height); this.width = width; this.height = height; } }
The constructor is a class method that uses the same name as the class: Rectangle
. In our sample Rectangle
class, the constructor receives two arguments of the double
type: width
and height
. The code within the constructor prints a message indicating that the code is initializing a new Rectangle
instance and prints the values for the width
and height
. This way, we will understand when the code within the constructor is executed. Because the constructor has an argument, it is known as a parameterized constructor.
Then, the following line assigns the width
double value received as an argument to the width
double field. We use this.width
to access the width
field for the instance and width
to reference the argument. The this
keyword provides access to the instance that has been created and we want to initialize, that is, the object that is being built. We use this.height
to access the height
field for the instance and height
to reference the argument.
The two lines before the constructor declare the width
and height
double field. These two fields are member variables that we can access without restrictions after the constructor finishes its execution.
The following lines create four instances of the Rectangle
class named rectangle1
, rectangle2
, rectangle3
, and rectangle4
. The code file for the sample is included in the java_9_oop_chapter_03_01
folder, in the example03_04.java
file.
Rectangle rectangle1 = new Rectangle(31.0, 21.0); Rectangle rectangle2 = new Rectangle(182.0, 32.0); Rectangle rectangle3 = new Rectangle(203.0, 23.0); Rectangle rectangle4 = new Rectangle(404.0, 14.0);
Each line that creates an instance specifies the type for the new variable (Rectangle
) followed by the variable name that will hold the reference to the new instance (rectangle1
, rectangle2
, rectangle3
, or rectangle4
). Then each line assigns the result of using the new
keyword followed by the desired value for the width
and height
arguments separated by a comma and enclosed in parentheses.
Tip
In Java 9, we have to specify the type for the variable in which we want to hold the reference to an instance. In this case, we declare each variable with the Rectangle
type. In case you have experience with other programming languages that provide a keyword to generate implicitly typed local variables such as the var
keyword in C#, you must know there is no equivalent in Java 9.
After we enter all the lines that declare the class and create the four instances in JShell, we will see four messages that say "Initializing a new Rectangle instance"
followed by the width and height values specified in the call to the constructor of each instance. The following screenshot shows the results of executing the code in JShell:
After we execute the previous lines, we can check the values for the width
and height
fields for each of the instances we have created. The following lines show expressions that JShell can evaluate to display the values for each field. The code file for the sample is included in the java_9_oop_chapter_03_01
folder, in the example03_05.java
file.
rectangle1.width rectangle1.height rectangle2.width rectangle2.height rectangle3.width rectangle3.height rectangle4.width rectangle4.height
The following screenshot shows the results of evaluating the previous expressions in JShell.
Enter the following expression in JShell. The code file for the sample is included in the java_9_oop_chapter_03_01
folder, in the example03_06.java
file.
rectangle1 instanceof Rectangle
JShell will display true
as a result of the evaluation of the previous expression because rectangle1
is an instance of the Rectangle
class. The instanceof
keyword allows us to test whether an object is of the specified type. With this keyword, we can determine whether an object is a Rectangle
object.
As previously explained, Rectangle
is a subclass of the java.lang.Object
class. JShell already imported all the types from java.lang
, and therefore, we can just reference this class as Object
. Enter the following expression in JShell. The code file for the sample is included in the java_9_oop_chapter_03_01
folder, in the example03_07.java
file.
rectangle1 instanceof Object
JShell will display true
as a result of the evaluation of the previous expression because rectangle1
is also an instance of the java.lang.Object
class.
Enter the following expression in JShell. The code file for the sample is included in the java_9_oop_chapter_03_01
folder, in the example03_08.java
file.
rectangle1.getClass().getName()
JShell will display "Rectangle"
as a result for the previous line because the rectangle1
variable holds an instance of the Rectangle
class. The getClass
method allows us to retrieve the runtime class of an object. The method is inherited from the java.lang.Object
class. The getName
method converts the runtime type to a string.
Now, we will try to create an instance of Rectangle
without providing arguments. The following line won't allow Java to compile the code and will display a build error in JShell because the compiler cannot find a parameterless constructor declared in the Rectangle
class. The only constructor declared for this class requires two double
arguments, and therefore, Java doesn't allow Rectangle
instances to be created without specifying the values for width
and height
. The code file for the sample is included in the java_9_oop_chapter_03_01
folder, in the example03_09.java
file.
Rectangle rectangleError = new Rectangle();
The next screenshot shows the detailed error message: