Declaration Order of Initializer Expressions – Object Lifetime

Declaration Order of Initializer Expressions

When an object is created using the new operator, instance initializer expressions are executed in the order in which the instance fields are declared in the class.

Java requires that the declaration of a field must occur before its usage in any initializer expression if the field is used on the right-hand side of an assignment in the initializer expression. This essentially means that the declaration of a field must occur before the value of the field is read in an initializer expression. Using the field on the left-hand side of an assignment in the initializer expression does not violate the declaration-before-reading rule, as this constitutes a write operation. This rule applies when the usage of the field is by its simple name.

There is one caveat to the declaration-before-reading rule: It does not apply if the initializer expression defines an anonymous class, as the usage then occurs in a different class that has its own accessibility rules in the enclosing context. The restrictions outlined earlier help to detect initialization anomalies at compile time.

In the next code example, the initialization at (2) generates a compile-time error because the field width in the initializer expression violates the declaration-before-reading rule. Because the usage of the field width in the initializer expression at (2) does not occur on the left-hand side of the assignment, this is an illegal forward reference. To remedy the error, the declaration of the field width at (4) can be moved in front of the declaration at (2). In any case, we can use the keyword this as shown at (3), but it will read the default value 0 in the field width.

Click here to view code image

class NonStaticInitializers {
  int length  = 10;                   // (1)
//double area = length * width;       // (2) Not OK. Illegal forward reference.
  double area = length * this.width;  // (3) OK, but width has default value 0.
  int width   = 10;                   // (4)
  int sqSide = height = 20;           // (5) OK. Legal forward reference.
  int height;                         // (6)
}

The forward reference at (5) is legal. The usage of the field height in the initializer expression at (5) occurs on the left-hand side of the assignment. The initializer expression at (5) is evaluated as (sqSide = (height = 20)). Every object of the class NonStaticInitializers will have the fields height and sqSide set to the value 20.

The declaration-before-reading rule is equally applicable to static initializer expressions when static fields are referenced by their simple names.

Example 10.1 shows why the order of field initializer expressions can be important. The initializer expressions in this example are calls to methods defined in the class, and methods are not subject to the same access rules as initializer expressions. The call at (2) to the method initMaxGuests() defined at (4) is expected to return the maximum number of guests, but the field occupancyPerRoom at (3) will not have been explicitly initialized at this point; therefore, its default value 0 will be used in the method initMaxGuests(), which will return a logically incorrect value. The program output shows that after object creation, the occupancy per room is correct, but the maximum number of guests is wrong.

Example 10.1 Initializer Expression Order and Method Calls

Click here to view code image

// File: TestOrder.java
class Hotel {
  private int noOfRooms        = 12;                                 // (1)
  private int maxNoOfGuests    = initMaxGuests();                    // (2) Bug
  private int occupancyPerRoom = 2;                                  // (3)
public int initMaxGuests() {                                       // (4)
    System.out.println(“occupancyPerRoom: ” + occupancyPerRoom);
    System.out.println(“maxNoOfGuests:    ” + noOfRooms * occupancyPerRoom);
    return noOfRooms * occupancyPerRoom;
  }
  public int getMaxGuests() { return maxNoOfGuests; }                // (5)
  public int getOccupancy() { return occupancyPerRoom; }             // (6)
}
//________________________________________________________________________
public class TestOrder {
  public static void main(String[] args) {
    Hotel hotel = new Hotel();                                       // (7)
    System.out.println(“AFTER OBJECT CREATION”);
    System.out.println(“occupancyPerRoom: ” + hotel.getOccupancy()); // (8)
    System.out.println(“maxNoOfGuests:    ” + hotel.getMaxGuests()); // (9)
  }
}

Output from the program:

occupancyPerRoom: 0
maxNoOfGuests:    0
AFTER OBJECT CREATION
occupancyPerRoom: 2
maxNoOfGuests:    0

Leave a Reply

Your email address will not be published. Required fields are marked *