© Kishori Sharan 2017
Kishori SharanBeginning Java 9 Fundamentalshttps://doi.org/10.1007/978-1-4842-2902-6_9

9. Constructors

Kishori Sharan
(1)
Montgomery, Alabama, USA
 
In this chapter, you will learn:
  • What constructors are and how to use them
  • Different types of initializers of a class
  • Declaring final variables, classes, and methods
  • What generic classes are and how to use them

What Is a Constructor?

A constructor is a named block of code that is used to initialize an object of a class immediately after the object is created. The structure of a constructor looks similar to a method. However, the similarity between the two stops right there, in their looks. They are two different constructs and they are used for different purposes.

Declaring a Constructor

The general syntax for a constructor declaration is as follows:
[modifiers] <constructor-name>(<parameters-list>) [throws-clause] {
    // Body of the constructor goes here
}
The declaration of a constructor starts with modifiers. A constructor can have its access modifier as public, private, protected, or package-level (no modifier). The constructor name is the same as the simple name of the class. The constructor name is followed by a pair of opening and closing parentheses, which may include parameters. Optionally, the closing parenthesis may be followed by a throws clause, which in turn is followed by a comma-separated list of exceptions. I discuss the use of the keyword throws in the chapter on exception handling. The body of the constructor, where you place your code, is enclosed in braces.
If you compare the syntax to declare a method with the syntax to declare a constructor, you will find that they are almost the same. It is suggested to keep the method declaration in mind when learning about constructor declaration because most of the characteristics are similar.
The following code shows an example of declaring a constructor for a class Test. Figure 9-1 shows the anatomy of the constructor.
A323069_2_En_9_Fig1_HTML.gif
Figure 9-1.
Anatomy of the constructor for the Test class
// Test.java
package com.jdojo.cls;
public class Test {
    public Test() {
        // Code goes here
    }
}
Tip
The name of a constructor must match the simple name, not the fully qualified name, of the class.
Unlike a method, a constructor does not have a return type. You cannot even specify void as a return type for a constructor. Consider the following declaration of a class Test2:
public class Test2 {
    // Below is a method, not a constructor.
    public void Test2() {   
        // Code goes here
    }
}
Does the class Test2 declare a constructor? The answer is no. The class Test2 does not declare a constructor. Rather, what you may be looking at is a method declaration, which has the same name as the simple name of the class. It is a method declaration because it specifies a return type of void. Note that a method name could also be the same as the class name, as is the case in this example.
Just the name itself does not make a method or constructor. If the name of a construct is the same as the simple name of the class, it could be a method or a constructor. If it specifies a return type, it is a method. If it does not specify a return type, it is a constructor.
When do you use a constructor? You use a constructor with the new operator to initialize an instance (or an object) of a class just after the new instance is created. Sometimes the phrases “create” and “initialize” are used interchangeably in the context of a constructor. However, you need to be clear about the difference in creating and initializing an object. The new operator creates an object and a constructor initializes that object.
The following statement uses a constructor of the Test class to initialize an object of the Test class:
Test t = new Test();
Figure 9-2 shows the anatomy of this statement . The new operator is followed by the call to the constructor. The new operator, along with the constructor call, for example "new Test()", is called an instance (or object) creation expression. An instance creation expression creates an object in memory, executes the code in the body of the specified constructor, and finally, returns the reference of the new object.
A323069_2_En_9_Fig2_HTML.gif
Figure 9-2.
Anatomy of a constructor call with the new operator
I have covered enough theories for declaring a constructor. It is time to see a constructor in action. Listing 9-1 has the code for a Cat class.
// Cat.java
package com.jdojo.cls;
public class Cat {
    public Cat() {
        System.out.println("Meow...");
    }
}
Listing 9-1.
A Cat Class with a Constructor
The Cat class declares a constructor. Inside the constructor’s body, it prints a message "Meow...". Listing 9-2 contains the code for a CatTest class , which creates two Cat objects in its main() method. Note that you always use an object creation expression to create a new object of the Cat class. It is up to you to store the reference of the new object in a reference variable. The first Cat object is created and its reference is not stored. The second Cat object is created and its reference is stored in a reference variable c.
// CatTest.java
package com.jdojo.cls;
public class CatTest {
    public static void main(String[] args) {
        // Create a Cat object and ignore its reference
        new Cat();
        // Create another Cat object and store its reference in c
        Cat c = new Cat();
    }
}
Listing 9-2.
A Test Class That Creates Two of the Cat Objects
Meow...
Meow...

Overloading a Constructor

A class can have more than one constructor. If a class has multiple constructors, they are called overloaded constructors . Since the name of the constructor must be the same as the simple name of the class, there is a need to differentiate one constructor from another. The rules for overloaded constructors are the same as for overloaded methods. If a class has multiple constructors, all of them must differ from the others in the number, order, or type of parameters. Listing 9-3 contains the code for a Dog class, which declares two constructors. One constructor accepts no parameters and another accepts a String parameter .
// Dog.java
package com.jdojo.cls;
public class Dog {
    // Constructor #1
    public Dog() {
        System.out.println("A dog is created.");
    }
    // Constructor #2
    public Dog(String name) {
        System.out.println("A dog named " + name + " is created.");
    }
}
Listing 9-3.
A Dog Class with Two Constructors, One with No Parameter and One with a String Parameter
If a class declares multiple constructors , you can use any of them to create an object of that class. For example, the following two statements create two objects of the Dog class:
Dog dog1 = new Dog();
Dog dog2 = new Dog("Cupid");
The first statement uses the constructor with no parameters and the second one uses the constructor with a String parameter. If you use a constructor with parameters to create an object, the actual parameter’s order, type, and number must match the formal parameter’s order, type, and number. Listing 9-4 has the complete code that creates two Dog objects using different constructors.
// DogTest.java
package com.jdojo.cls;
public class DogTest {
    public static void main(String[] args) {
        Dog d1 = new Dog();         // Uses Constructor #1
        Dog d2 = new Dog ("Canis"); // Uses Constructor #2
    }
}
Listing 9-4.
Testing the Constructors of the Dog Class
A dog is created.
A dog named Canis is created.
The output of running the DogTest class indicates that different constructors are called when two Dog objects are created in the main() method.
A constructor is called once per object creation expression. You can execute the code for one constructor only once in the process of an object creation. If the code for a constructor is executed N times, it means N number of objects of that class will be created and you must use N number of object creation expressions to do that. However, when an object creation expression calls a constructor, the called constructor may call another constructor from its body. I cover this scenario where one constructor calls another later in this section.

Writing Code for a Constructor

So far, you have been writing trivial code in constructors. What kind of code should you write in a constructor? The purpose of a constructor is to initialize the instance variables of the newly created object. Inside a constructor, you should restrict yourself only to write code that initializes instance variables of the object. An object is not fully created when a constructor is called. The object is still in the process of creation. If you write some processing logic in a constructor assuming that a full blown object exists in memory, sometimes you may get unexpected results. Let’s create another class to represent a dog object. You will call this class SmartDog, as shown in Listing 9-5.
// SmartDog.java
package com.jdojo.cls;
public class SmartDog {
    private String name;
    private double price;
    public SmartDog() {
        // Initialize the name to “Unknown” and the price to 0.0
        this.name = "Unknown";
        this.price = 0.0;
        System.out.println("Using SmartDog() constructor");
    }
    public SmartDog(String name, double price) {
        // Initialize name and price instance variables with the
        // values of the name and price parameters
        this.name = name;
        this.price = price;
        System.out.println("Using SmartDog(String, double) constructor");
    }
    public void bark() {
        System.out.println(name + " is barking...");
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return this.name;
    }
    public void setPrice(double price) {
        this.price = price;
    }
    public double getPrice() {
        return this.price;
    }
    public void printDetails() {
        System.out.print("Name: " + this.name);
        if (price > 0.0) {
            System.out.println(", price: " + this.price);
        } else {
            System.out.println(", price: Free");
        }
    }
}
Listing 9-5.
A SmartDog Class That Declares Two Constructors to Initialize Instance Variables Differently
The SmartDog class looks a little bigger. However, its logic is very simple. The following are the main points in the SmartDog class that you need to understand:
  • It declares two instance variables; they are name and price. The name instance variable stores the name of a smart dog. The price instance variable stores the price for which it can be sold.
  • It declares two constructors. The first constructor has no parameters. It initializes the name and price instance variables to "Unknown" and 0.0, respectively. The second constructor accepts two parameters named name and price. It initializes the name and price instance variables to whatever values are passed for the two parameters. Note the use of the keyword this inside the constructors. The keyword this refers to the object for which the constructor’s code is executing. The use of the keyword this is not necessary in the first constructor. However, you must use the keyword this to refer to instance variables in the second constructor because the names of the formal parameters hide the names of the instance variables.
  • The two constructors initialize instance variables (or state of the object) in their bodies. They do not include any other processing logic.
  • The instance method bark() prints a message on the standard output with the name of the smart dog who is barking.
  • The setName() and getName() methods are used to set and get the name of the smart dog. The setPrice() and getPrice() methods are used to set and get the price of the smart dog.
  • The printDetails() method prints the name and price of a smart dog. If the price for a smart dog is not set to a positive value, it prints the price as "Free".
Listing 9-6 has the code for a SmartDogTest class that demonstrates how the two constructors initialize the instance variables.
// SmartDogTest.java
package com.jdojo.cls;
public class SmartDogTest {
    public static void main(String[] args) {
        // Create two SmartDog objects
        SmartDog sd1 = new SmartDog();
        SmartDog sd2 = new SmartDog("Nova", 219.2);
        // Print details about the two dogs
        sd1.printDetails();
        sd2.printDetails();
        // Make them bark
        sd1.bark();
        sd2.bark();
        // Change the name and price of Unknown dog
        sd1.setName("Opal");
        sd1.setPrice(321.80);
        // Print details again
        sd1.printDetails();
        sd2.printDetails();
        // Make them bark one more time
        sd1.bark();
        sd2.bark();
    }
}
Listing 9-6.
A Test Class to Demonstrate the Use of the SmartDog Class
Using SmartDog() constructor
Using SmartDog(String, double) constructor
Name: Unknown, price: Free
Name: Nova, price: 219.2
Unknown is barking...
Nova is barking...
Name: Opal, price: 321.8
Name: Nova, price: 219.2
Opal is barking...
Nova is barking...

Calling a Constructor from Another Constructor

A constructor may call another constructor of the same class. Let’s consider the following Test class. It declares two constructors; one accepts no parameters and one accepts an int parameter.
public class Test {
    Test() {
    }
    Test(int x) {
    }
}
Suppose you want to call the constructor with an int parameter from the constructor with no parameter. Your first attempt, which is wrong, would be as follows:
public class Test {
    Test() {
        // Call another constructor
        Test(103); // A compile-time error
    }
    Test(int x) {
    }
}
The previous code does not compile. Java has a special way to call a constructor from another constructor. You must use the keyword this, as if it is the name of the constructor, to call a constructor from another constructor. The following code calls the constructor with an int parameter from the constructor with no parameter using the statement, "this(103);". This is another use of the keyword this.
public class Test {
    Test() {
        // Call another constructor
        this(103); // OK. Note the use of the keyword this.
    }
    Test(int x) {
    }
}
There are two rules about calling a constructor from another constructor. The rules ensure that one constructor is executed only once during the process of an object creation of a class. These rules are as follows:
  • The call to another constructor must be the first statement in the constructor.
  • A constructor cannot call itself.
If a constructor calls another constructor, it must be the first executable statement in the constructor’s body. This makes it easy for the compiler to check that a constructor has been called and it has been called only once. For example, the following code will generate a compile-time error because a call to the constructor with int parameter this(k) is the second statement inside the constructor’s body, not the first statement.
public class Test {
    Test() {
        int k = 10; // First statement
        this(k);    // Second statement. A compile-time error
    }
    Test(int x) {
    }
}
An attempt to compile the code for this Test class will generate the following error message:
Error(4):  call to this must be first statement in constructor
A constructor cannot call itself because it will result in a recursive call. In the following code for the Test class , both constructors attempt to call themselves:
public class Test {
    Test() {
        this();
    }
    Test(int x ) {
        this(10);
    }
}
An attempt to compile this code will result in the following error. One error message is generated for each attempt to call the constructor itself.
Error(2):  recursive constructor invocation
Error(6):  recursive constructor invocation
Typically, you create overloaded constructors for a class when you have many ways to initialize an object of the class. Let’s consider the SmartDog class shown in Listing 9-5. Two constructors give you two ways to initialize a new SmartDog object. The first one initializes the name and the price with default values. The second constructor lets you initialize name and price with the value supplied by the caller. Sometimes you may perform some logic to initialize the object inside a constructor. Letting you call another constructor from a constructor allows you to write such logic only once. You can use this feature for your SmartDog class , as shown:
// SmartDog.java
package com.jdojo.cls;
public class SmartDog {
    private String name;
    private double price;
    public SmartDog() {
        // Call another constructor with "Unknown" and 0.0 as parameters
        this("Unknown", 0.0);
        System.out.println("Using SmartDog() constructor");
    }
    public SmartDog(String name, double price) {
        // Initialize name and price to specified name and price
        this.name = name;
        this.price = price;
        System.out.println("Using SmartDog(String, double) constructor");
    }
    /* Rest of code remains the same */
}
Note that you changed the code only inside the constructor that accepts no parameters. Instead of setting the default values for name and price in the first constructor, you called the second constructor with the default values as parameters from the first one.

Using a return Statement Inside a Constructor

A constructor cannot have a return type in its declaration. It means a constructor cannot return any value. Recall that a return statement is of two types: one with a return expression and one without a return expression. The return statement without a return expression simply returns the control to the caller without returning any value. You can use a return statement without a return expression inside a constructor body. When a return statement in a constructor is executed, the control returns to the caller, ignoring the rest of the constructor’s code.
The following code shows an example of using a return statement in a constructor. If the parameter x is a negative number, the constructor simply executes a return statement to end the call to the constructor. Otherwise, it performs some logic.
public class Test {
    public Test(int x) {
        if (x < 0) {
            return;
        }
        /* Perform some logic here */
    }
}

Access Level Modifier for a Constructor

Access level for a constructor determines the part of the program that can use that constructor in an object creation expression to create an object of that class. Similar to fields and methods, you can specify one of the four access levels for a constructor:
  • public
  • private
  • protected
  • <package-level>
The following code declares four constructors for the Test class . A comment for each constructor explains its access level.
// Class Test has public access level
public class Test {
    // Constructor #1 - package-level access
    Test() {  
    }
    // Constructor #2 - public access level
    public Test(int x) {    
    }
    // Constructor #3 - private access level
    private Test(int x, int y) {    
    }
    // Constructor #4 - protected access level
    protected Test(int x, int y, int z){    
    }
}
The effect of these access levels is the same as their effect on a method. A constructor with a public access level can be used in any part of the application provided the class itself is accessible. A constructor with private access level can be used only inside the same class in which it is declared. A constructor with protected access level can be used in any part of the program in the same package in which its class is declared and inside any descendant class in any package. A constructor with package-level access can be used inside the same package in which its class is declared.
You can specify public or package-level access level for a class. A class defines a new reference type, which you can use to declare a reference variable. The access level of a class determines in which part of the program the name of the class can be used. Usually, you use the name of a class in a cast or in a reference variable declaration as shown:
// Test class name is used to declare the reference variable t
Test t;
// Test class name is used to cast the reference variable xyz
Test t2 = (Test)xyz;
Let’s discuss the different combinations of access levels for a class and its constructor, and its effects in a program. Consider the following code that declares a class T1 with public access level. It also has a constructor, which also has a public access level:
// T1.java
package com.jdojo.cls.p1;
public class T1 {
    public T1() {
    }
}
Because the class T1 has a public access level , you can declare a reference variable of type T1 anywhere in the same module. If this code is in a different module, assume that the module containing the class exports the class' package and the module having this code reads the first module:
// Code inside any package
T1 t;
Because the constructor for the class T1 has a public access level, you can use it in an object creation expression in any package.
// Code inside any package
new T1();
You can combine the previous two statements into one in the code in any package.
// Code inside any package
T1 t = new T1();
Let’s consider the following code for the class T2, which has a public access level and has a constructor with a private access level:
// T2.java
package com.jdojo.cls.p1;
public class T2 {
    private T2() {
    }
}
Because class T2 has a public access level, you can use its name to declare a reference variable in any package in the same module. If the package is in a different module, assume that the module can read the package that contains the T2 class. The constructor for class T2 has a private access level. The implication of having a private constructor is that you cannot create an object of the T2 class outside the T2 class. Recall that a private method, field, or a constructor cannot be used outside the class in which it is declared. Therefore, the following code will not compile unless it appears inside the T2 class:
// Code outside the T2 class
new T2(); // A compile-time error
What is the use of the T2 class if you cannot create its object outside of the T2 class? Let’s consider the possible situations where you can declare a constructor private , and still create and use objects of the class.
A constructor is used to create an object of a class . You may want to restrict the number of objects of a class. The only way you can restrict the number of objects of a class is by having full control over its constructors. If you declare all constructors of a class to have the private access level, you have full control over how the objects of that class will be created. Typically, you include one or more public static methods in that class, which create and/or return an object of that class. If you design a class so that only one object of the class may exist, it is called a singleton pattern . The following code is a version of the T2 class that is based on the singleton pattern.
// T2.java
package com.jdojo.cls.p1;
public class T2 {
    private static T2 instance = new T2();
    private T2() {
    }
    public static T2 getInstance() {
        return T2.instance;
    }
    /* Other code goes here */
}
The T2 class declares a private static reference variable called instance , which holds the reference of an object of the T2 class. Note that the T2 class uses its own private constructor to create an object. Its public static getInstance() method returns the lone object of the class. More than one object of the T2 class cannot exist.
You can use the T2.getInstance() method to get the reference of an object of the T2 class. Internally, the T2 class does not create a new object every time you call the T2.getInstance() method. Rather, it returns the same object reference for all calls to this method.
T2 t1 = T2.getInstance();
T2 t2 = T2.getInstance();
Sometimes you want a class to have only static members. It may not make sense to create an object of such a class. For example, the java.lang.Math class declares its constructor private. The Math class contains static variables and static methods to perform numeric operations. It does not make sense to create an object of the Math class.
You can also declare all constructors of a class private to prevent inheritance. Inheritance lets you define a class by extending the definition of another class. If you do not want anyone else to extend your class, one way to achieve this is to declare all constructors of your class private. Another way to prevent your class from being extended is to declare it final. I discuss inheritance in detail in Chapter 20.
Let’s consider the class T3 whose constructor has protected access level as shown:
// T3.java
package com.jdojo.cls.p1;
public class T3 {
    protected T3() {
    }
}
A constructor with protected access level can be used anywhere in the same package or inside a descendant class in any package. The class T3 is in the com.jdojo.cls.p1 package. You can write the following statement anywhere in com.jdojo.cls.p1 package, which creates an object of the T3 class:
// Valid anywhere in the com.jdojo.cls.p1 package
new T3();
I cover inheritance in detail later. However, to complete the discussion of a protected constructor, you will use inheritance in the following example. Things about inheritance will be clearer when I discuss it in Chapter 20. You inherit (or extend) a class using the keyword extends. The following code creates a T3Child class by inheriting it from the T3 class:
// T3Child.java
package com.jdojo.cls.p2;
import com.jdojo.cls.p1.T3;
public class T3Child extends T3 {
    public T3Child() {
        super(); // Ok. Calls T3() constructor, which is declared protected.
    }
}
The T3 class is called the parent class of the T3Child class. An object of a child class cannot be created until the object of its parent class is created. Note the use of the super() statement inside T3Child() constructor’s body. The statement super() calls the protected constructor of the T3 class. The super keyword is used to call the parent class' constructor as you use the keyword this to call another constructor of the same class. You cannot call the protected constructor of T3 directly as this is outside the com.jdojo.cls.p1 package:
new T3();
Consider a T4 class with a constructor having package-level access. Recall that using no access level modifier gives package-level access.
// T4.java
package com.jdojo.cls.p1;
public class T4 {
    // T4() has package-level access
    T4() {
    }  
}
You can use T4’s constructor to create its object anywhere in the com.jdojo.cls.p1 package. Sometimes you need a class that works as a helper class for other classes in a package. Objects of these classes need to be created only within the package. You can specify package-level access for constructors of such helper classes.

Default Constructor

The primary goal of declaring a class is to create an object of its type. You need a constructor to create an object of a class. The necessity to have a constructor for a class is so obvious that the Java compiler adds a constructor to your class if you do not declare one. The constructor that is added by the compiler is called the default constructor. The default constructor does not have any parameters. Sometimes the default constructor is also called a no-args constructor . The access level of the default constructor is the same as the access level of the class.
The classes that you have been working with are called top-level classes. You can also declare a class within another class, which is called an inner class . A top-level class can have public or package-level access. However, an inner class can have public, private, protected, or package-level access. The Java compiler adds a default constructor for a top-level class as well as for a nested class . A default constructor for a top-level class can have either public or package-level access, depending on the access level of the class. However, a default constructor for an inner class can have access level of public, private, protected or package-level, depending on its class access level.
Table 9-1 shows a few examples of classes and the compiler adding a default constructor to them. When the compiler adds a default constructor, it also adds a statement called super() to call the no-args constructor of the parent class. Sometimes the call to the parent’s no-args constructor inside the default constructor may cause your class not to compile. Refer to Chapter 20 for a complete discussion on this topic.
Table 9-1.
Examples of Classes for Which a Default Constructor Is Added by the Java Compiler
Source Code for Your Class
Compiled Version of Your Class
Comments
public class Test {
}
public class Test {
    public Test() {
    }
}
The compiler adds a default constructor with public level access.
class Test {
}
class Test {
    Test() {
    }
}
The compiler adds a default construct with package-level access.
public class Test {
    Test() {
    }
}
public class Test {
    Test() {
    }
}
The Test class already had a constructor. The compiler does not add any constructor.
public class Test {
    public Test(int x) {
    }
}
public class Test {
    public Test(int x) {
    }
}
The Test class already had a constructor. The compiler does not add any constructor.
public class Test {
    private class Inner {
    }
}
public class Test {
    public Test() {
    }
    private class Inner {
        private Inner(){
        }
    }
}
Test is a public top-level class and Inner is a private inner class. The compiler adds a public default constructor for the Test class and a private default constructor for the Inner class.
Tip
It is good programming practice to add a constructor explicitly to all your classes rather than letting the compiler add a default constructor for your classes. The story of constructors is not over yet. You will revisit constructors in the chapter on inheritance.

A static Constructor

Constructors are used in the context of the creating a new object; hence, they are considered part of the object context, not the class context. You cannot declare a constructor static. The keyword this, which is a reference to the current object, is available inside the body of constructors, as it is available inside the body of all instance methods.

Instance Initialization Block

You have seen that a constructor is used to initialize an instance of a class. An instance initialization block , also called instance initializer, is also used to initialize objects of a class. Why does Java provide two constructs to perform the same thing?
Not all classes in Java can have a constructor. Are you surprised to learn that not all classes can have constructors? I did not mention this fact during the discussion on constructors. Briefly, I mentioned inner classes, which are different from top-level classes. I discuss one more type of class in volume II of this three-book series called an anonymous class . As the name suggests, an anonymous class does not have a name. Recall that a constructor is a named block of code whose name is the same as the simple name of the class. Because an anonymous class cannot have a name, it cannot have a constructor either. How will you initialize an object of an anonymous class? You can use an instance initializer to initialize an object of an anonymous class. The use of an instance initializer to initialize an object is not limited only to anonymous classes. Any type of class can use it to initialize its objects.
An instance initializer is simply a block of code inside the body of a class, but outside any methods or constructors. Recall that a block of code is a sequence of legal Java statements enclosed within braces. An instance initializer does not have a name. Its code is simply placed inside an opening brace and a closing brace. The following snippet of code shows how to declare an instance initializer for a Test class. Note that an instance initializer is executed in instance context and the keyword this is available inside the instance initializer.
public class Test {
    private int num;
    // An instance initializer
    {
        this.num = 101;
        /* Other code for the instance initializer goes here */
    }
    /* Other code for Test class goes here */
}
You can have multiple instance initializers for a class. All of them are executed automatically in textual order for every object you create. Code for all instance initializers is executed before any constructors. Listing 9-7 demonstrates the sequence in which the constructor and instance initializers are executed.
// InstanceInitializer.java
package com.jdojo.cls;
public class InstanceInitializer {
    {
        System.out.println("Inside instance initializer 1.");
    }
    {
        System.out.println("Inside instance initializer 2.");
    }
    public InstanceInitializer() {
        System.out.println("Inside no-args constructor.");
    }
    public static void main(String[] args) {
        InstanceInitializer ii = new InstanceInitializer();    
    }
}
Listing 9-7.
Example of Using an Instance Initializer
Inside instance initializer 1.
Inside instance initializer 2.
Inside no-args constructor.
Tip
An instance initializer cannot have a return statement. It cannot throw checked exceptions unless all declared constructors list those checked exceptions in their throws clause; an exception to this rule is made in the case of an anonymous class because it does not have a constructor; an instance initializer of an anonymous class may throw checked exceptions.

static Initialization Block

A static initialization block is also known as a static initializer. It is similar to an instance initialization block. It is used to initialize a class. In other words, you can initialize class variables inside a static initializer block. An instance initializer is executed once per object, whereas a static initializer is executed only once for a class when the class definition is loaded into JVM. To differentiate it from an instance initializer, you need to use the static keyword at the beginning of its declaration. You can have multiple static initializers in a class. All static initializers are executed in textual order in which they appear and are executed before any instance initializers. Listing 9-8 demonstrates when a static initializer is executed.
// StaticInitializer.java
package com.jdojo.cls;
public class StaticInitializer {
    private static int num;
    // An instance initializer
    {   
        System.out.println("Inside instance initializer.");
    }
    // A static initializer. Note the use of the keyword static below.
    static {
        num = 1245;
        System.out.println("Inside static initializer.");
    }
    // Constructor
    public StaticInitializer() {
        System.out.println("Inside constructor.");
    }
    public static void main(String[] args) {
        System.out.println("Inside main() #1. num: " + num);
        // Declare a reference variable of the class
        StaticInitializer si;
        System.out.println("Inside main() #2. num: " + num);
        // Create an object
        new StaticInitializer();
        System.out.println("Inside main() #3. num: " + num);
        // Create another object
        new StaticInitializer();
    }
}
Listing 9-8.
An Example of Using a static Initializer in a Class
Inside static initializer.
Inside main() #1. num: 1245
Inside main() #2. num: 1245
Inside instance initializer.
Inside constructor.
Inside main() #3. num: 1245
Inside instance initializer.
Inside constructor.
The output may be confusing at first. It shows that the static initializer has executed even before the first message is displayed in the main() method . You get the output when you run the StaticInitializer class using the following command:
c:Java9Fundamentals>java --module-path dist --module jdojo.cls/com.jdojo.cls.StaticInitializer
The java command must load the definition of the StaticInitializer class before it can execute its main() method. When the definition of the StaticInitializer class is loaded into memory, at that time the class is initialized and its static initializer is executed. This is the reason that you see the message from the static initializer before you see the message from the main() method. Note that instance initializer is called twice because you create two objects of the StaticInitializer class.
Tip
A static initializer cannot throw checked exceptions and it cannot have a return statement.

The final Keyword

The final keyword is used in many contexts in a Java. It takes on different meanings in different contexts. However, as its name suggests, its primary meaning is the same in all contexts. Its primary meaning is as follows:
The construct with which the final keyword is associated does not allow modifying or replacing the original value or definition of the construct.
If you remember the primary meaning of the final keyword, it will help you understand its specialized meaning in a specific context. The final keyword can be used in the following three contexts:
  • A variable declaration
  • A class declaration
  • A method declaration
In this section, I discuss the use of the final keyword only in the context of a variable declaration . Chapter 20 discusses its use in the context of class and method declarations in detail. In this section, I briefly describe its meaning in all three contexts.
If a variable is declared final, it can be assigned a value only once. That is, the value of a final variable cannot be modified once it has been set. If a class is declared final, it cannot be extended (or subclassed). If a method is declared final, it cannot be redefined (overridden or hidden) in the subclasses of the class that contains the method.
Let’s discuss the use of the final keyword in a variable declaration. In this discussion, a variable declaration means the declaration of a local variable, a formal parameter of a method/constructor, an instance variable, and a class variable. To declare a variable as final, you need to use the final keyword in the variable’s declaration. The following snippet of code declares four final variables: YES, NO, MSG, and act:
final int YES = 1;
final int NO = 2;
final String MSG = "Good-bye";
final Account act = new Account();
You can set the value of a final variable only once. Attempting to set the value of a final variable the second time will generate a compile-time error.
final int x = 10;
int y = 101 + x; // Reading x is ok
// A compile-time error. Cannot change value of the final variable x once it is set
x = 17;
There are two ways to initialize a final variable:
  • You can initialize it at the time of its declaration.
  • You can defer its initialization until a later time.
How long you can defer the initialization of a final variable depends on the variable type. However, you must initialize the final variable before it is read the first time.
If you do not initialize a final variable at the time of its declaration, such a variable is known as a blank final variable . The following is an example of declaring a blank final variable.
// A blank final variable
final int multiplier;
/* Do something here... */
// Set the value of multiplier first time
multiplier = 3;
// Ok to read the multiplier variable
int value = 100 * multiplier;
Let’s go through examples of each type of variable and see how to declare them final.

final Local Variables

You can declare a local variable final. If you declare a local variable as a blank final variable, you must initialize it before using. You will receive a compile-time error if you try to change the value of the final local variable the second time. The following snippet of code uses final and blank final local variables in a test() method. Comments in the code explain what you can do with the final variables in the code.
public static void test() {
    int x = 4;        // A variable    
    final int y = 10; // A final variable. Cannot change y here onward
    final int z;      // A blank final variable
    // We can read x and y, and modify x
    x = x + y;
    /* We cannot read z here because it is not initialized yet */
    /* Initialize the blank final variable z */
    z = 87;
    /* Can read z now. Cannot change z here onwards */
    x = x + y + z;
    /* Perform other logic here... */
}

final Parameters

You can also declare a formal parameter final. A formal parameter is initialized automatically with the value of the actual parameter when the method or the constructor is invoked. Therefore, you cannot change the value of a final formal parameter inside the method’s or the constructor’s body. The following snippet of code shows the final formal parameter x for a test2() method:
public void test2(final int x) {
    // Can read x, but cannot change it
    int y = x + 11;
    /* Perform other logic here... */
}

final Instance Variables

You can declare an instance variable final and blank final. An instance variable is a part of an object’s state. A final instance variable specifies part of the object’s state that does not change after the object is created. A blank final instance variable must be initialized when an object is created. The following rules apply to initializing a blank final instance variable:
  • It must be initialized in one of the instance initializers or all constructors. The following rules expand on this rule.
  • If it is initialized in an instance initializer, it should not be initialized again in any other instance initializers or constructors.
  • If it is not initialized in any of the instance initializers, the compiler makes sure it is initialized only once, when any of the constructors is invoked. This rule can be broken into two sub-rules. As a rule of thumb, a blank final instance variable must be initialized in all constructors. If you follow this rule, a blank final instance variable will be initialized multiple times if a constructor calls another constructor. To avoid multiple initialization of a blank final instance variable, it should not be initialized in a constructor if the first call in the constructor is a call to another constructor, which initializes the blank final instance variable.
These rules for initializing a blank final instance variable may seem complex. However, it is simple to understand if you remember only one rule—that a blank final instance variable must be initialized once and only once when any of the constructors of the class is invoked. All of the previously described rules are to ensure that this rule is followed.
Let’s consider different scenarios of initializing final and blank final instance variables. We do not have anything to discuss about final instance variables where x is a final instance variable for the Test class:
public class Test {
    private final int x = 10;
}
The final instance variable x has been initialized at the time of its declaration and its value cannot be changed afterward. The following code shows a Test2 class with a blank final instance variable named y:
public class Test2 {
    private final int y; // A blank final instance variable
}
Attempting to compile the Test2 class generates an error because the blank final instance variable y is never initialized. Note that the compiler will add a default constructor for the Test2 class, but it will not initialize y inside the constructor. The following code for the Test2 class will compile because it initializes y in an instance initializer:
public class Test2 {     
    private final int y;
    {
        y = 10; // Initialized in an instance initializer
    }
}
The following code will not compile because it initializes y more than once inside two instance initializers :
public class Test2 {     
    private final int y;
    {
        y = 10; // Initialized y for the first time
    }
    {
        y = 10; // An error. Initializing y again
    }
}
This code may seem legal to you. However, it is not legal because two instance initializers are initializing y, even though both of them set y to the same value, 10. The rule is about number of times a blank final instance variable should be initialized, irrespective of the value being used for its initializations. Since all instance initializers are executed when an object of the Test2 class is created, y will be initialized twice, which is not legal.
The following code for the class Test2 with two constructors would compile:
public class Test2 {
    private final int y;
    public Test() {
        y = 10; // Initialize y
    }
    public Test(int z) {
        y = z; // Initialize y
    }
}
This code initializes the blank final instance variable y in both constructors. It may seem that y is being initialized twice—once in each constructor. Note that y is an instance variable and one copy of y exists for each object of the Test2 class. When an object of the Test2 class is created, it will use one of the two constructors, not both. Therefore, for each object of the Test2 class, y is initialized only once.
The following is the modified code for the Test2 class, which presents a tricky situation. Both constructors initialize the blank final instance variable y. The tricky part is that the no-args constructor calls another constructor.
public class Test2 {
    private final int y;
    public Test() {
        this(20); // Call another constructor
        y = 10;   // Initialize y
    }
    public Test(int z) {
        y = z; // Initialize y
    }
}
This code for the Test2 class does not compile. The compiler generates an error message, which reads as “variable y might already have been assigned". Let’s consider creating an object of the Test2 class as follows:
Test2 t = new Test2(30);
There is no issue in creating an object of the Test2 class by invoking the one-arg constructor. The blank final instance variable y is initialized only once. Let’s create an object of the Test2 class.
Test2 t2 = new Test2();
When the no-args constructor is used, it calls the one-arg constructor, which initializes y to 20. The no-args constructor initializes y again to 10, which is the second initialization for y. For this reason, the previous code for the Test2 class would not compile. You need to remove the initialization of y from the no-args constructor and the code would then compile. The following is the modified code for the Test2 class that would compile:
public class Test2 {
    private final int y;
    public Test() {
        this(20); // Another constructor will initialize y
    }
    public Test(int z) {
        y = z; // Initialize y
    }
}

final Class Variables

You can declare a class variable final and blank final. You must initialize a blank final class variable in one of the static initializers. If you have more than one static initializer for a class, you must initialize all the blank final class variables only once in one of the static initializers.
The following code for the Test3 class shows how to deal with a final class variable. It is customary to use all uppercase letters to name final class variables. It is also a way to define constants in Java programs. The Java class library has numerous examples where it defines public static final variables to use them as constants.
public class Test3 {
    public static final int YES = 1;
    public static final int NO = 2;
    public static final String MSG;
    static {
        MSG = "I am a blank final static variable";
    }
}

final Reference Variables

Any type of variables (primitive and reference) can be declared final. The primary meaning of the final keyword is the same in both cases. That is, the value stored in a final variable cannot be changed once it has been set. I cover the final reference variable in a little more detail in this section. A reference variable stores the reference of an object. A final reference variable means that once it references an object (or null), it cannot be modified to reference another object. Consider the following statement:
final Account act = new Account();
Here, act is a final reference variable of the Account type. It is initialized at the time of its declaration. At this time, act is referencing an object in memory.
Now, you cannot make the act variable reference another object in memory. The following statement generates a compile-time error:
act = new Account(); // A compile-time error. Cannot change act
A common misconception arises in this case. Mistakenly, programmers believe that the Account object that is referenced by the act reference variable cannot be changed. The declaration statement of the act reference variable as final has two things.
  • An act as a reference variable, which is final.
  • An Account object in memory whose reference is stored in the act variable.
It is the act reference variable that cannot be changed, not the Account object it is referencing. If the Account class allows you to change the state of its object, you can change the state using the act variable. The following are valid statements, which modify the balance instance variable of the Account object:
act.deposit(2001.00); // Modifies state of the Account object
act.debit(2.00);      // Modifies state of the Account object
If you do not want an object of a class to be modified after it is created, you need to include that logic in the class design. The class should not let any of its instance variables be modified after the object is created. Such objects are called immutable objects.

Compile-Time vs. Runtime final Variables

You use final variables to define constants. This is the reason that final variables are also called constants. If the value of a final variable can be computed by the compiler at compile-time, such a variable is a compile-time constant. If the value of a final variable cannot be computed by the compiler, it is a runtime final variable. The values of all blank final variables are not known until runtime. References are not computed until runtime. Therefore, all blank final variables and final reference variables are runtime constants.
Java performs an optimization when you use compile-time constants in an expression. It replaces the use of the compile-time constant with the actual value of the constant. Suppose you have a Constants class as follows, which declares a static final variable named MULTIPLIER:
public class Constants {
    public static final int MULTIPLIER = 12;
}
Consider the following statement:
int x = 100 * Constants.MULTIPLIER;
When you compile this statement, the compiler will replace Constants.MULTIPLIER with its value 12 and your statement is compiled as follows:
int x = 100 * 12;
Now, 100 * 12 is also a compile-time constant expression. The compiler will replace it with its value 1200 and your original statement will be compiled as follows:
int x = 1200;
There is one downside of this compiler optimization. If you change the value of the MULTIPLIER final variable in the Constants class, you must recompile all the classes that refer to the Constants.MULTIPLIER variable. Otherwise, they will continue using the old value of the MULTIPLIER constant that existed when they were compiled last time.

Generic Classes

Abstraction and polymorphism are at the heart of object-oriented programming . Defining a variable is an example of abstraction where the variable hides the actual values and the location where the values are stored. Defining a method hides the details of its implementation logic, which is another form of abstraction. Defining parameters for a method is part of polymorphism that allows the method to work on different types of values or objects.
Java has a feature called generics that allows for writing true polymorphic code in Java. Using generics, you can write code without knowing the type of the objects your code operates on. It lets you create generic classes, constructors, and methods.
A generic class is defined using formal type parameters. Formal type parameters are a list of comma-separated variable names placed in angle-brackets (<>) after the class name in the class declaration. The following snippet of code declares a generic class Wrapper that takes one formal type parameter:
public class Wrapper<T>  {
    // Code for the Wrapper class goes here
}
The parameter has been given a name T. What is T at this point? The answer is that you do not know. All you know at this point is that T is a type variable, which could be any reference type in Java, such as String, Integer, Double, Human, Account, etc. The formal type parameter value is specified when the Wrapper class will be used. The classes that take formal type parameters are also known as parameterized classes .
You can declare a variable of the Wrapper<T> class by specifying the String type as the value for its formal type parameter as shown here. Here, String is the actual type parameter.
Wrapper<String> stringWrapper;
Java lets you use a generic class without specifying the formal type parameters. This is allowed for backward compatibility. You can also declare a variable of the Wrapper<T> class as shown:
Wrapper aRawWrapper;
When a generic class is used without specifying the actual type parameters, it is known as raw type. The previous declaration used the Wrapper<T> class as a raw type, as it did not specify the value for T.
Tip
The actual type parameter for a generic class, if specified, must be a reference type, for example, String, Human, etc. Primitive types are not allowed as the actual type parameters for a generic class.
A class may take more than one formal type parameter. The following snippet of code declares a Mapper class that takes two formal parameters named T and R:
public class Mapper<T,R>  {
    // Code for the Mapper class goes here
}
You can declare variable of the Mapper<T, R> class as follows:
Mapper<String,Integer> mapper;
Here, the actual type parameters are String and Integer.
It is customary, not a requirement , to give one-character names to the formal type parameters, for example, T, R, U, V, etc. Typically, T stands for “Type”, R for “Return,” etc. One-character names make the code more readable. However, nothing stops you from declaring a generic class as follows, which has four formal type parameters named MyType, YourType, Hello, and WhoCares.
public class Fun<MyType,YourType,Hello,WhoCares> {
    // Code for the Fun class goes here
}
Java will compile the Fun class, but readers of your code will complain for sure! The formal type parameters are available inside the class body to be used as types. Listing 9-9 declares a generic class Wrapper<T>.
// Wrapper.java
package com.jdojo.cls;
public class Wrapper<T> {
    private T obj;
    public Wrapper(T obj) {
        this.obj = obj;
    }
    public T get() {
        return obj;
    }
    public void set(T obj) {
        this.obj = obj;
    }
}
Listing 9-9.
Declaring a Generic Class Wrapper<T>
The Wrapper<T> class uses the formal type parameter to declare instance variable obj to declare a formal parameter for its constructor and set() method, and as a return type for the get() method.
You can create an object of the generic type by specifying the actual type parameter for the constructor as follows:
Wrapper<String> w1 = new Wrapper<String>("Hello");
Most of the time, the compiler can infer the actual type parameter for the constructor. In those cases, you can omit the actual type parameter. In the following assignment statement, the compiler will infer the actual type parameter for the constructor as String:
Wrapper<String> w1 = new Wrapper<>("Hello");
Once you have declared a variable of the generic class , you can think of the formal type parameter as the specified actual type parameter for all practical purposes. Now, you can think that, for w1, the get() method of the Wrapper<T> class returns a String.
String s1 = w1.get();
The program in Listing 9-10 shows how to use the generic Wrapper<T> class.
// WrapperTest.java
package com.jdojo.cls;
public class WrapperTest {
    public static void main(String[] args) {
        Wrapper<String> w1 = new Wrapper<>("Hello");
        String s1 = w1.get();
        System.out.println("s1=" + s1);
        w1.set("Testing generics");
        String s2 = w1.get();
        System.out.println("s2=" + s2);
        w1.set(null);
        String s3 = w1.get();
        System.out.println("s3=" + s3);
    }
}
Listing 9-10.
Using a Generic Class in Your Code
s1=Hello
s2=Testing generics
s3=null
This is just the tip of the iceberg when it comes to what generics offer in Java. To understand generics completely, you must cover other topics, such as inheritance, first. Generics are covered fully in a separate chapter in the second volume of this three-book series.

Summary

A constructor is a named block of code that is used to initialize an object of a class immediately after the object is created. The structure of a constructor looks similar to a method. However, they are two different constructs and they are used for different purposes. The name of a constructor is the same as the simple name of the class. Like methods, constructors may accept parameters. Unlike methods, constructors cannot specify a return type. A constructor is used with the new operator, which allocates memory for a new object and the constructor initializes the new object. A constructor does not return a value to its caller. You can use a return statement without an expression inside a constructor. The return statement ends the constructor call and returns the controls to the caller.
Constructors are not considered members of the class. Like fields and methods, constructors also have an access level: public, private, protected, and package-level. The presence of the keyword public, private, and protected in defining them gives them public, private, and protected access level, respectively. Absence of any of these keywords specifies the package-level access.
A class can have more than one constructor. If a class has multiple constructors, they are called overloaded constructors. Since the name of the constructor must be the same as the simple name of the class, there is a need to differentiate one constructor from another. All constrictors of a class must differ from the others in the number, order, or type of parameters.
A constructor may call another constructor of the same class using the keyword this as if it were a method name. If a constructor of a class calls another constructor of the same class, the following rules must be met:
  • The call to another constructor must be the first statement in the constructor.
  • A constructor cannot call itself.
If you do not add a constructor to your class, the Java compiler adds one. Such as constructor is called a default constructor. The default constructor has the same access level as its class and it takes no parameters.
A class can also have one or more instance initializers to initialize objects of the class. An instance initializer is simply a block of code inside the body of a class, but outside any methods or constructors. Recall that a block of code is a sequence of legal Java statements enclosed within braces. An instance initializer does not have a name. Its code is simply placed inside an opening brace and a closing brace. When an object of a class is created, all instance initializers of the class are executed in textual order. Typically, instance initializers are used to initialize an object of an anonymous class.
A class can have one or more static initializers, which are used to initialize a class, typically, class variables. An instance initializer is executed once per object, whereas a static initializer is executed only once for a class when the class definition is loaded into JVM. To differentiate it from an instance initializer, you need to use the static keyword in the beginning of its declaration. All static initializers of a class are executed in textual order in which they appear and are executed before any instance initializers.
You can define a class and its members final. If something is final, it means its definition or value, whatever it represents, cannot be modified. Final variables are used to define constants in Java. Compile-time constants are constants whose values are known when the program is compiled. Runtime constants are constants whose values are not known until the program is run.
A variable can be declared blank final, in which case the variable is declared final, but not assigned a value at the time of declaration. A blank final variable must be assigned a value before its value is read. A blank final instance variable must be initialized once in its instance initializers or constructors. You can declare a class variable as blank final. You must initialize a blank final class variable in one of the static initializers. If you have more than one static initializer for a class, you must initialize all the blank final class variables only once in one of the static initializers.
Java allows you to write true polymorphic code using generics in which code is written in terms of formal type parameters. A generic class is defined using formal type parameters. Formal type parameters are a list of comma-separated variable names placed in angle-brackets (<>) after the class name in the class declaration. Classes that take formal type parameters are also known as parameterized classes . The actual type parameters are specified when the parameterized classes are used.
Exercises
  1. 1.
    What is a constructor? What is the name of the operator that must be used along with a constructor to create an object of a class?
     
  2. 2.
    What is a default constructor? What is the access level of a default constructor?
     
  3. 3.
    How do you call a constructor of a class from another constructor of the same class? Describe any restrictions where such a call should be placed in the code.
     
  4. 4.
    What are static and instance initializers?
     
  5. 5.
    What are final variables and blank final variables?
     
  6. 6.
    What is the effect of declaring a method's parameter or a constructor’s parameter final?
     
  7. 7.
    Consider the following code for a Cat class:
    // Cat.java
    package com.jdojo.cls.excercise;
    public class Cat {
    }
    When the Cat class is compiled, the compiler will add a default constructor to it. Rewrite the Cat class as if you are adding the default constructor instead of the compiler.
     
  8. 8.
    Consider the following code for a Mouse class:
    // Mouse.java
    package com.jdojo.cls.excercise;
    class Mouse {
    }
    When the Mouse class is compiled, the compiler will add a default constructor to it. Rewrite the Mouse class as if you are adding the default constructor instead of the compiler.
     
  9. 9.
    Create a SmartPoint2D class with two int instance variables named x and y. The instance variables should be declared private and final. An instance of the SmartPoint2D class represents an immutable point in a 2D plane. That is, once an object of the SmartPoint2D class is created, the x and y values of that object cannot be changed. Add a public constructor to the class, which should accept the values for the two instance variables x and y and initialize them with the passed-in values.
     
  10. 10.
    Add getters for the x and y instance variables in the SmartPoint2D class that you created in the previous exercise.
     
  11. 11.
    Add a public static final variable named ORIGIN to the SmartPoint2D class. The ORIGIN variable is of the SmartPoint2D class and it is a SmartPoint2D with x = 0 and y = 0.
     
  12. 12.
    Implement a method named distance in the SmartPoint2D class that you created in the previous exercise. The method accepts an instance of the SmartPoint2D class and returns the distance between the current point and the point represented by the parameter. The method should be declared as follows:
    public class SmartPoint2D {
        /* Code from the previous exercise goes here. */
        public double distance(SmartPoint2D p) {
            /* Your code for this exercise goes here. */
        }
    }
    Hint: The distance between two points (x1, y1) and (x2, y2) is computed as $$ sqrt{{left(x1-x2
ight)}^2+{left(y1-y2
ight)}^2} $$. You can use Math.sqrt(n) method to compute the square root of a number n.
     
  13. 13.
    Create a Circle class that has three private final instance variables named x, y, and radius. The x and y instance variables represent the x and y coordinates of the center of the circle; they are of int data type. The radius instance variable represents the radius of the circle; it is of the double data type. Add a constructor to the Circle class that accepts the values for its instance variables x, y, and radius. Add getters for the three instance variables.
     
  14. 14.
    Enhance the Circle class by adding four instance methods named centerDistance, distance, overlaps, and touches. All these methods accept a Circle as a parameter. The centerDistance method returns the distance (as a double) between the centers of the circle and another circle passed in as the parameter. The distance method returns the minimum distance (as a double) between the two circles. If two circles overlap, the distance method returns a negative number. The overlaps method returns true if two circles overlaps, false otherwise. The touches method returns true if two circles touches each other, false otherwise. The distance method must use the centerDistance method. The body of the overlaps and touches methods must contain only one statement that uses the distance method.
    Hint: The distance between two circles is the distance between their centers minus their radii. Two circles overlap if the distance between them is negative. Two circles touch if the distance between them is zero.
     
  15. 15.
    Enhance the Circle class by adding two methods named perimeter and area that compute and return the perimeter and area of the circle, respectively.
     
  16. 16.
    Add a second constructor to the Circle class that takes a double parameter, which is the radius of the circle. This constructor should call another existing constructor of the Circle class with three parameters passing zero as the values for x and y.
     
  17. 17.
    A double value can be NaN, positive infinity, and negative infinity. Enhance the constructor of the Circle class with three parameters, x, y, and radius, so it throws a RuntimeException when the value of the radius parameter is not a finite number or a negative number.
    Hint: The java.lang.Double class contains a static isFinite(double n) method, which returns true if the specified parameter n is a finite number, false otherwise. Use the following statement to throw a RuntimeException:
    throw new RuntimeException(
               "Radius must be a finite non-negative number.");
     
  18. 18.
    Consider the following InitializerTest class. How many static and instance initializers are in this class? What will be printed when this class is run?
    // InitializerTest.java
    package com.jdojo.cls.excercise;
    public class InitializerTest {
        private static int count;
        {
            System.out.println(count++);
        }
        {
            System.out.println(count++);
        }
        static {
            System.out.println(count);
        }
        public static void main(String[] args) {
            new InitializerTest();
            new InitializerTest();
        }
    }
     
  19. 19.
    Describe why the following FinalTest class does not compile.
    // FinalTest.java
    package com.jdojo.cls.excercise;
    public class FinalTest {
        public static int square(final int x) {
            x = x * x;        
            return x;
        }
    }
     
  20. 20.
    Describe why the following BlankFinalTest class does not compile.
    // BlankFinalTest.java
    package com.jdojo.cls.excercise;
    public class BlankFinalTest {
        private final int x;
        private final int y;
        {
            y = 100;
        }
        public BlankFinalTest() {
            y = 100;
        }
        /* More code goes here */
    }
     
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.94.209