The Essence of OOP using Java, Instance Initializers

Baldwin explains the use of instance initializers, static initializers in conjunction with constructors, and the initialization of ordinary instance variables. He explains and demonstrates the order in which they are executed.

Published:  August 19, 2003
By Richard G. Baldwin

Java Programming Notes # 1634


Preface

This series of lessons is designed to teach you about the essence of Object-Oriented Programming (OOP) using Java.

The first lesson in the series was entitled The Essence of OOP Using Java, Objects, and Encapsulation.  The previous lesson was entitled The Essence of OOP using Java, Static Initializer Blocks.

You may find it useful to open another copy of this lesson in a separate browser window.  That will make it easier for you to scroll back and forth among the different figures and listings while you are reading about them.

For further reading, see my extensive collection of online Java tutorials at Gamelan.com. A consolidated index is available at www.DickBaldwin.com.

Preview

Proper initialization is important

As I mentioned in the previous lesson in this series, proper initialization of variables is an important aspect of programming.   Unlike other programming languages, it is not possible to write a Java program in which the variables are accidentally initialized with the garbage left over in memory from the programs that previously ran in the computer.

Automatic initialization to default values

Instance variables and class (static) variables are automatically initialized to standard default values if you fail to purposely initialize them.  Although local variables are not automatically initialized, you cannot compile a program that fails to either initialize a local variable or assign a value to that local variable before it is used.

Thus, Java programmers are prevented from committing the cardinal sin of allowing their variables to be initialized with random garbage through programming negligence.

Initialization during declaration

You should already know that you can initialize instance variables and class variables when you declare them, by including an initialization expression in the variable declaration statement.  Figure 1 shows an example of a primitive instance variable named simpleInitTime that is purposely initialized to a long value obtained by invoking a static method of the Init02 class named relTime(You will learn more about this method later.)

  long simpleInitTime = Init02.relTime();
Figure 1

While the expression in Figure 1 is a little complex, it is still just an expression and is perfectly suitable for use in initializing an instance variable when it is declared.

Constructor

What if your initialization requirements are more complex than can be satisfied with a single initialization expression?  You should already know that you can write one or more overloaded constructors to purposely initialize all instance variables when an object is instantiated from the class.  The code in a constructor can be as complex as you need it to be.

Not all classes allow constructors

What you may not know, however, is that you cannot always write a constructor for a class when you define it.  For example, anonymous classes, which we will study in a subsequent lesson, do not allow the definition of a constructor.

However, even anonymous classes allow you to write instance initializer blocks when you define the class.  The code in an instance initializer block, which can also be quite complex, is executed when an object is instantiated from the class.

Not as powerful as a constructor

You can write any number of instance initializer blocks in your class definition.  However, unlike constructors, instance initializer blocks do not receive parameters.  Therefore, they are less powerful than constructors.  In terms of power, instance initializer blocks fall between simple initialization expressions (such as that shown in Figure 1) and constructors.  Because they can execute complex code, they are more powerful than simple initialization expressions.  Because they cannot receive parameters, they are less powerful than constructors.

Similar to noarg constructors

An instance initializer block is similar to a constructor that doesn't receive any parameters, except that you can write any number of instance initializer blocks into your class definition, and you can only write one noarg constructor in your class definition.

The order of execution

The code in an instance initializer block is executed after the constructor for the superclass is executed, and before the constructor for the class to which the initializer belongs is executed.

If the class definition contains a combination of instance initializer blocks in combination with the declaration of instance variables with initialization expressions, the code that comprises those items is executed in the order in which it appears in the class definition.

The order of execution of instance initializers in combination with instance variable initializations, constructors, and static initializer blocks will be illustrated in the sample program that I will discuss later in this lesson.

What does Flanagan have to say?

Here is how one of my favorite authors, David Flanagan of Java in a Nutshell fame, summarizes the situation:

"An instance initializer is simply a block of code inside curly braces that is embedded in a class definition, where a field or method definition normally appears.  A class (any class -- not just anonymous classes) can have any number of instance initializers.  The instance initializers and any variable initializers that appear in field definitions for the class are executed in the order they appear in the Java source code.  These initializers are automatically run after the superclass constructor has returned but before the constructor, if any, of the current class runs."

Why do we need instance initializers?

Flanagan goes on to explain the value of instance initializers, not only for anonymous classes, but also for non-anonymous classes.  According to Flanagan,

"Instance initializers allow you to initialize an object's fields near the definition of those fields, rather than deferring that initialization to a constructor defined further away in the class.  Used in this way, they can sometimes improve code readability."

The sample program that I will discuss in the next section will illustrate many aspects of instance initializers in combination with static initializer blocks, constructors, and simple instance variable initializations.

Discussion and Sample Code

I will discuss and explain a Java program named Init02 in this lesson.  (A complete listing of the program is provided in Listing 15 near the end of the lesson.)  As mentioned above, this program illustrates many aspects of instance initializers in combination with static initializer blocks, constructors, and simple instance variable initializations.

Description of the program

Instance initializers behave much like noarg constructors.  They are particularly useful for anonymous classes, which are not allowed to define any constructors, even those that take no arguments.  However, the syntax for anonymous classes, even in the absence of instance initializers, is very cryptic.  Therefore, I decided to explain and illustrate instance initializers in the context of ordinary top-level classes rather than to combine that explanation with the explanation of anonymous classes in a subsequent lesson.

The class hierarchy

This program defines a class named B that extends a class named A.  Parameterized constructors are used in both A and B to instantiate an object of the class named B.  

The base time is recorded

The controlling class defines and initializes a static variable containing the time that the program starts running in milliseconds relative to 00:00:00 GMT, Jan 1, 1970. This value is used as the base for computing time intervals later as the execution of the program progresses.

The times that are computed and displayed later are in milliseconds relative to the time at which the program started running.

The class loading process

Static initializers are defined in both A and B to display the time that the two classes are loaded and the order in which they are loaded.  You will see that both classes are loaded when an attempt is made to instantiate an object of the subclass B.  You will also see that the superclass is loaded before the subclass is loaded, and both are loaded before the object is instantiated.

An initialized instance variable

An instance variable is defined in the class named B and is initialized (using a simple initialization expression) with the time in milliseconds that the variable is initialized.  In addition, two separate instance initializers are defined in the class named B that perform initialization after the constructor for A completes execution and before the constructor for B begins execution.

In terms of physical location, the instance variable mentioned above follows the first of the two instance initializers and appears before the second instance initializer in the class definition.

The order of execution

The first of the two instance initializers executes before the instance variable is initialized. The second of the two initializers executes after the instance variable is initialized, demonstrating that initialization based on simple initialization expressions and instance initializers occurs in the order that the code appears in the class definition.

Initialization time is displayed

The two constructors (for classes A and B) and the two initializers each display time information when they are executed to show the order in which the constructors and the initializers are executed.

Two separate objects

Two separate instances (objects) of the class named B are created, showing not only the order in which the instance initializers and the constructors are executed, but also showing that the static initializers are executed one time only when the classes are first loaded.

Display values of instance variables

Each time an object of the class named B is instantiated, an instance method of the class is invoked to display the values of the instance variables initialized during the process of instantiating the object.

One-hundred millisecond delays

Several one-hundred millisecond time delays are purposely inserted at strategic points within the program to force the time intervals between the different steps in the program to be measurable.  Otherwise, the time intervals between steps would be so small that it would not be possible to distinguish between them on the basis of time recorded in milliseconds.

Will discuss in fragments

I will discuss the program code in fragments.  In discussing the fragments, I will present much of the code in the order that it is executed, which is not necessarily the same order that the code appears in the program.

As mentioned earlier, a complete listing of the program can be viewed in Listing 15 near the end of the lesson.

Two utility methods

I will begin by presenting two static utility methods that are used to simplify the code in the body of the program.  Both of these methods are defined in the controlling class named Init02.

Relative time in milliseconds

The utility method named relTime, shown in Listing 1, is used to compute and return the current time in milliseconds relative to a time value stored in a static variable of the controlling class named baseTime.  As you will see later, baseTime contains the time that the program started running.  Thus, each time this method is called, it returns the current time relative to the time that the program started running.

  static long relTime(){
return ((new Date().getTime()) - baseTime);
}//end printTime

Listing 1

I relegated this code to a utility method simply due to the length and complexity of the expression, and the large number of times that the relative time is needed throughout the program.

Insert a delay

The utility method shown in Listing 2 causes the current thread to sleep for one-hundred milliseconds.  Thus, each time this method is called, it inserts a one-hundred millisecond delay in the execution of the program
.

  static void delay(){
try{
Thread.currentThread().sleep(100);
}catch(Exception e){e.printStackTrace();}
}//end delay

Listing 2

This method is also called numerous times throughout the program.  Once again, therefore, I relegated this code to a utility method to simplify the code in the body of the program.

Establish the start time

Listing 3 shows the beginning of the controlling class named Init02, including the declaration and initialization of the class variable named baseTime.

public class Init02{
static long baseTime = new Date().getTime();

Listing 3

According to the Sun documentation, the getTime method of the Date class in Listing 3
"Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT represented by this Date object."
Thus, this variable will contains the time in milliseconds that the class named Init02 is loaded, which is also the time that the program starts running.  This time will serve as the base time against which various time intervals will be computed during the running of the program.

The main method

The code in Listing 4 shows the beginning of the main method, which displays the current time relative to the start time, and instantiates a new object of the class named B.  In addition, the code in Listing 4 invokes the method named showData on the new object.  The showData method displays the values stored in several instance values as various initialization steps are completed during the instantiation of the object.

  public static void main(String[] args){

System.out.println("Instantiate first obj: "
+ relTime());

new B("Construct 1").showData();

Listing 4

The output

As you have probably already guessed, the print statement in Listing 4 produces the output shown in Figure 2.  In other words, there was less than one millisecond of elapsed time between the initialization of the static variable named baseTime and the invocation of the relTime method in Listing 4.

Instantiate first obj: 0
Figure 2

Load classes A and B

The instantiation of the new object in Listing 4 triggers a whole chain of events.  I will discuss those events in the sequence in which they occur in the paragraphs that follow.  The first pair of interesting events is the loading of the classes named A and B.

What does it mean to say that a class is loaded?


As I explained in a previous lesson, I can't provide a description of exactly what happens from a technical viewpoint.  However, I can tell you what seems to happen from a functional viewpoint.

Functionally, an object of the class whose name is Class is created and saved in memory.  This object represents the class that is being loaded (in this case, two classes named A and B are loaded, so two separate Class objects are created).  From that point forward, all static members of the class are available to the program by referring to the name of the class and the name of the member.  Other information about the class is also available by invoking methods, such as the method named
getSuperclass, on a reference to the Class object.

As you will see, when an attempt is made to instantiate an object of the subclass named B, that class and its superclass named A are both loaded.  Furthermore, the superclass named A is loaded first.  The loading of both classes takes place before the other steps required to instantiate the object take place.

A static initializer in the class named A

Listing 5 shows the beginning of the class named A.  The code in Listing 5 declares an instance variable named aXstrTime, which will be used later to record the time that the constructor for the class named A is executed.  More important for this part of the discussion, however, is the static initializer shown in Listing 5.

class A{
long aXstrTime;

static{//This is a static initializer.
System.out.println("Class A loaded: " +
Init02.relTime());
}//End static initializer


Listing 5

You will recall from the previous lesson on static initializers that they execute one time only when the class is loaded.  The static initializer in Listing 5 prints a message showing the time that the class named A is loaded.

Class A load time

On my machine the code in Listing 5 produced the output shown in Figure 3.  Presumably, the ten-millisecond delay between the start of the program and the point in time that the class named A was loaded was due primarily to the time required for the program to find the class file on the disk and to load it into memory.  Your system may produce a different result depending on the speed of your computer.

Class A loaded: 10
Figure 3

A static initializer in the class named B

Listing 6 shows the beginning of the class named B.  The code in Listing 6 declares three instance variables, which will be used later to record the time that the constructor and the instance initializers are executed.  More important for this part of the discussion, however, is the static initializer shown in Listing 6.

class B extends A{
long bXstrTime;
long init1Time;
long init2Time;

static{//This is a static initializer.
Init02.delay();

System.out.println("Class B loaded: " +
Init02.relTime() + "\n");
}//End static initializer


Listing 6

The output

The static initializer in Listing 6 purposely inserts a one-hundred millisecond delay and then prints the time that it finishes executing.  This is the time that the class named B finishes loading.

Class B loaded: 110
Figure 4

Figure 4 shows that the class named B was loaded immediately following the loading of the class named A.

Create the new object of the class named B

After the classes are loaded, the system proceeds to create the new instance of the class named B.  You should recall however that objects are actually created beginning with the contribution from the class named Object, and proceeding down the inheritance hierarchy to the class from which the object is actually being instantiated.  Thus, the next identifiable significant event is the execution of the constructor for the class named A, which is the superclass of the class named B.  (Nothing in the program makes it possible for us to identify the construction of that portion of the object attributable to the superclass named Object.)

The constructor for the class named A

Listing 7 shows the constructor for the class named A.  The code in the constructor purposely inserts a one-hundred millisecond delay, and then gets and saves the time that the constructor is executed.  (The time is saved in the instance variable named aXstrTime, which was declared in Listing 5 earlier.)

  A(String str){//constructor

Init02.delay();

aXstrTime = Init02.relTime();
System.out.println(str + "A: " + aXstrTime);
}//end constructor for A

Listing 7

Then the code in the constructor prints that time, producing the output shown in Figure 5.

Construct 1A:  210
Figure 5

The important point here is that the constructor for the superclass is executed after the classes named A and B are loaded, but before the instance initializers for the subclass named B are executed.

Instance initializers in the subclass named B


If you examine Listing 15 near the end of the lesson you will see that the class named B contains two separate instance initializers, which are physically separated by an ordinary instance variable declaration (with initialization) and a constructor.  As you will see in the discussion that follows, the execution of the first instance initializer follows the execution of the constructor for the superclass named A shown in Listing 7.

Then the initialization of the ordinary instance variable takes place, following the execution of the first instance initializer.  This is followed by the execution of the second instance initializer.

Despite their physical placement in the code, the execution of both instance initializers and the initialization of the ordinary instance variable all take place before the constructor for the class named B is executed.

The first instance initializer

The first instance initializer is shown in Listing 8.  Once again, as described by David Flanagan,
"An instance initializer is simply a block of code inside curly braces that is embedded in a class definition, where a field or method definition normally appears. ... The instance initializers and any variable initializers that appear in field definitions for the class are executed in the order they appear in the Java source code.  These initializers are automatically run after the superclass constructor has returned but before the constructor, if any, of the current class runs."

  {//This is an instance initializer
Init02.delay();

init1Time = Init02.relTime();

System.out.println("Initializer-1: " +
init1Time);

Init02.delay();
}//end instance initializer

Listing 8

Insert a delay

The code in the instance initializer in Listing 8 begins by inserting a one-hundred millisecond delay to force the time interval between the execution of the constructor for the class named A and the execution of the instance initializer to be distinguishable.

Get, save, and display the relative time


After sleeping for one-hundred milliseconds, the code in the initializer gets and saves the current time relative to the start of the program.

Then the code in the initializer displays that time, producing the output shown in Figure 6.

Initializer-1: 310
Figure 6

If you compare Figure 6 with Figure 5 showing the time that the constructor for the class named A was executed, you will see that the printout produced by the initializer followed the printout produced by the constructor by the one-hundred millisecond delay introduced at the beginning of the initializer.  This confirms that the first initializer in the class named B was executed following the execution of the constructor for the superclass named A.

Insert another time delay

Finally the instance initializer shown in Listing 8 inserts an additional one-hundred millisecond delay.  This makes it possible to distinguish the time that the ordinary instance variable (to be discussed next) was initialized from the time that the print statement in the first instance initializer was executed.

An ordinary instance variable

Listing 9 shows the declaration and initialization of an ordinary instance variable named simpleInitTime.  Recall that the physical location of this variable declaration is after the first instance initializer and before the constructor and the second instance initializer.

  long simpleInitTime = Init02.relTime();

Listing 9

Although the code in Listing 9 doesn't display the time of initialization, code later in the program causes the value stored in the variable named simpleInitTime to be displayed, producing the output shown in Figure 7.

class B simple init: 410
Figure 7

As you can see from the relative time shown in Figure 7, the instance variable was initialized immediately following completion of execution of the first instance initializer shown in Listing 8 (compare Figure 7 with Figure 6).

The second instance initializer

An examination of Listing 15 near the end of the lesson shows that the class named B contains a second instance initializer, separated from the first instance initializer by an ordinary instance variable declaration and a constructor.  The second instance initializer is shown in Listing 10.

  {//This is another instance initializer

Init02.delay();

init2Time = Init02.relTime();

System.out.println("Initializer-2: " +
init2Time);
}//end instance initializer

Listing 10

Insert a delay

This initializer begins by inserting a one-hundred millisecond delay.  Then it gets, saves, and displays the time relative to the start time for the program as shown in Figure 8.

Initializer-2: 510
Figure 8

A comparison of the relative time shown in Figure 8 with Figure 7 confirms that the second instance initializer was executed after the initialization of the ordinary instance variable shown in Listing 9.  This confirms that the instance initializers and variable initializers are executed in the order they appear in the Java source code.

The constructor for the class named B

The constructor for the class named B physically separates the two instance initializers in the class definition.  The code for the constructor begins in Listing 11.

  B(String str){
super(str);

Listing 11

The constructor begins by using the super keyword to invoke a parameterized constructor on the superclass named A.
(If you are unfamiliar with this use of the super keyword, see Lesson 1628 entitled The Essence of OOP using Java, The this and super Keywords at www.DickBaldwin.com.)
Insert a time delay

The remaining code in the constructor, as shown in Listing 12, inserts a one-hundred millisecond time delay.

    Init02.delay();

bXstrTime = Init02.relTime();
System.out.println(str + "B: " + bXstrTime);
}//end constructor for B

Listing 12

Get and display the time

Then the constructor gets, saves, and displays the time, producing the output shown in Figure 9.  A comparison of the relative time shown in Figure 9 with the previous figures confirms that the
initializers are run after the superclass constructor has returned but before the constructor of the current class runs.

Construct 1B:  611
Figure 9

The showData method

The class named B contains a method named showData.  This method is shown in its entirety in Listing 13.  The purpose of this method is to summarize the order of initialization by displaying the values stored in the various instance variables as the object was being instantiated.

  void showData(){
System.out.println(
"\nInitialization values:");
System.out.println("class A xstr: " +
aXstrTime);
System.out.println("class B init-1: " +
init1Time);
System.out.println("class B simple init: " +
simpleInitTime);
System.out.println("class B init-2: " +
init2Time);
System.out.println("class B xstr: " +
bXstrTime);
System.out.println();//blank line
}//end showData

Listing 13

The output of the showData method

The values stored in the instance variables are displayed in the order that the initialization steps took place during the instantiation of the object.  Recall that the showData method was invoked on the object when it was instantiated in the main method in Listing 4, producing the output shown in Figure 10.

Initialization values:
class A xstr: 210
class B init-1: 310
class B simple init: 410
class B init-2: 510
class B xstr: 611
Figure 10

An examination of Figure 10 makes it clear that the superclass constructor was executed first, at a relative time of 210 milliseconds.  This was followed by execution of the first instance initializer at 310 milliseconds, initialization of the ordinary instance variable at 410 milliseconds, and execution of the second instance initializer at 510 milliseconds.  Finally the constructor for the class named B was executed at a relative time of 611 milliseconds.

Instantiate another object

Listing 14 shows the remaining code in the main method, which was not previously discussed.

    delay();

System.out.println("Instantiate second obj: "
+ relTime());
new B("Construct 2").showData();
}//end main

Listing 14

The remaining code in the main method inserts another one-hundred millisecond delay, and then instantiates another object of the class named B.  As before, this triggers a whole series of events, many of which produce output on the screen.

The screen output

The output produced by instantiating another object is shown in its entirety in Figure 11.

Instantiate second obj: 711
Construct 2A: 811
Initializer-1: 911
Initializer-2: 1111
Construct 2B: 1211

Initialization values:
class A xstr: 811
class B init-1: 911
class B simple init: 1011
class B init-2: 1111
class B xstr: 1211
Figure 11

Except for the differences in the relative time values, the output shown in Figure 11 matches that shown in Figure 2 and Figures 5 through 10.  Note, however, that there is nothing in Figure 11 corresponding to the output previously shown in Figures 3 and 4.

Classes are not reloaded

Figures 3 and 4 show the output produced by the execution of the static initializers in the classes named A and B.  The process of instantiating another object from a set of previously loaded classes does not cause those classes to be reloaded.  Since static initializers are executed one time only when the class is first loaded, those initializers are not executed when the second object is instantiated from the class named B.

Constructors and instance initializers are executed for each object

However, constructors and instance initializers are executed, and ordinary instance variables are initialized each time a new object is instantiated.  Therefore, the output shown in Figure 11 contains messages and time tags corresponding to the execution of both constructors, the execution of both instance initializers, and the initialization of an ordinary instance variable, all in the proper order.

Run the Program

At this point, you may find it useful to compile and run the program shown in Listing 15 near the end of the lesson.

Summary

Static initializer blocks

A static initializer is a block of code surrounded by curly braces that is embedded in a class definition and is qualified by the keyword static.

You can include any number of static initializer blocks within your class definition.  They can be separated by other code such as method definitions and constructors.  The static initializer blocks will be executed in the order that they appear in the code, regardless of the other code that may separate them.

The static initializers belonging to a class are executed one time only when the class is loaded.

Instance initializers

An instance initializer is a block of code surrounded by curly braces that is embedded in a class definition.  (It is not qualified by the keyword static.)  You can include any number of instance initializers in your class definition, and the initializers may be physically separated by other items, such as constructors, method definitions, variable declarations, etc.

Instance initializers and variable initializers, along with constructors, are executed each time a new object of the class is instantiated.  The instance initializers and variable initializers are executed in the order that they appear in the Java source code.  They are executed after the constructor for the superclass is executed, and before the constructor for the current class is executed.

Instance initializers are especially useful in anonymous classes (to be explained in a future lesson).  However, they can be included in any class definition, and may make code more readable by initializing instance variables near the declaration of those variables rather than deferring that initialization to a constructor that is located further away in the class definition.

Instance initializers are very similar to noarg constructors, except that a class can define only one noarg constructor, but can define any number of instance initializers.  A class definition can contain instance initializers in addition to a noarg constructor, in which case, the instance initializers will be executed before the noarg constructor is executed.

What's Next?

The next lesson in this series will explain and discuss inner classes, with special emphasis on member classes.  Subsequent lessons will explain local classes, anonymous classes, and top-level nested classes.

Complete Program Listing

A complete listing of the program discussed in this lesson is show in Listing 15 below.

/*File Init02.java
Copyright 2003 R.G.Baldwin

Illustrates the use of instance initializers.

Instance initializers behave much like noarg
constructors, and are particularly useful for
anonymous classes, which are not allowed to
define any constructors, even those that take no
arguments.

This program defines a class named B that extends
a class named A. Parameterized constructors are
used in both A and B to instantiate an object of
the class named B.

The controlling class defines and initializes
a static variable containing the time that the
program starts running in msec. This value is
used as the base for computing time intervals
later as the execution of the program progresses.
The times that are computed and displayed later
are in msec relative to the time at which the
program starts running.

Static initializers are defined in both A and B
to display the time that the two classes are
loaded and the order in which they are loaded.

An instance variable is defined in the class
named B and is initialized (using a simple
initialization expression) with the time in msec
that the variable is initialized. The physical
location of the instance variable follows the
first of two instance initializer in the class
definition.

In addition, two separate instance initializers
are defined in the class named B that perform
initialization after the constructor for A
completes execution and before the constructor
for B begins execution. The first of these
initializers executes before the instance
variable mentioned above is initialized. The
second of these initializers executes after the
instance variable is initialized, demonstrating
that initialization based on simple
initialization expressions and instance
initializers occurs in the order that the code'
appears in the class definition.

The two constructors and the two initializers
each get and print time information when they are
executed to show the order in which the
constructors and the initializers are executed.

Two separate instances of the class named B are
created, showing not only the order in which the
instance initializers and the constructors are
executed, but also showing that the static
initializers are executed one time only when the
classes are loaded.

Each time an object of the class named B is
instantiated, an instance method of the class
is invoked to display the values of the instance
variables initialized during the process
of instantiating the object of the class named B.

100-msec time delays are purposely inserted at
strategic points within the program in order to
force the time intervals between the occurrence
of the different steps in the program to be
measurable.

The output for one run is shown below. Your
results may be different depending on the speed
of your computer.

Instantiate first obj: 0
Class A loaded: 10
Class B loaded: 110

Construct 1A: 210
Initializer-1: 310
Initializer-2: 510
Construct 1B: 611

Initialization values:
class A xstr: 210
class B init-1: 310
class B simple init: 410
class B init-2: 510
class B xstr: 611

Instantiate second obj: 711
Construct 2A: 811
Initializer-1: 911
Initializer-2: 1111
Construct 2B: 1211

Initialization values:
class A xstr: 811
class B init-1: 911
class B simple init: 1011
class B init-2: 1111
class B xstr: 1211

Note the 100-msec elapsed time intervals
between the various steps in the execution of the
program. Also note the order in which the class
loading operations and the initialization steps
occur.

Tested using SDK 1.4.1 under WinXP
************************************************/
import java.util.Date;

public class Init02{
//Establish the base time in msec.
static long baseTime = new Date().getTime();


//This is a utility method used to insert a
// 100-millisecod delay.
static void delay(){
try{
Thread.currentThread().sleep(100);
}catch(Exception e){e.printStackTrace();}
}//end delay
//-------------------------------------------//

//This is a utility method used to compute the
// current time relative to the value stored
// in the static variable named baseTime.
static long relTime(){
return ((new Date().getTime()) - baseTime);
}//end printTime

//-------------------------------------------//

public static void main(String[] args){
//Invoke a parameterized constructor for the
// class named B, which is a subclass of A.
// Also invoke the showData method on that
// object to display the values of the
// instance variables that were initialized
// during the construction of the object.
System.out.println("Instantiate first obj: "
+ relTime());
new B("Construct 1").showData();
//Sleep 100 msec and then instantiate another
// object.
delay();
System.out.println("Instantiate second obj: "
+ relTime());
new B("Construct 2").showData();
}//end main
//-------------------------------------------//
}//end class Init02
//=============================================//

class A{
long aXstrTime;

static{//This is a static initializer, which is
// run one time only when the class is loaded.
//Print a message showing the time that the
// class finishes loading.
System.out.println("Class A loaded: " +
Init02.relTime());
}//End static initializer
//-------------------------------------------//

A(String str){//constructor
//Sleep for 100 msec before completing this
// construction
Init02.delay();

//Record the time of construction and print
// a message showing the construction time.
aXstrTime = Init02.relTime();
System.out.println(str + "A: " + aXstrTime);
}//end constructor for A

}//end class A
//=============================================//

class B extends A{
long bXstrTime;
long init1Time;
long init2Time;

static{//This is a static initializer, which is
// run one time only when the class is loaded.
//Sleep for 100 msec to show the order
// that the classes named A and B are loaded.
Init02.delay();
//Print a message showing the time that the
// class finishes loading.
System.out.println("Class B loaded: " +
Init02.relTime() + "\n");
}//End static initializer
//-------------------------------------------//

{//This is an instance initializer
//Sleep for 100 msec before doing this
// initialization.
Init02.delay();
//Record the time and print a message showing
// the time that this instance initializer
// was executed.
init1Time = Init02.relTime();
System.out.println("Initializer-1: " +
init1Time);

//Sleep for 100 msec after doing this
// initialization to separate this
// initialization from the initialization of
// the instance variable that follows.
Init02.delay();
}//end instance initializer
//-------------------------------------------//

//Note that this initialized instance variable
// is located after the first instance
// initializer and before the second instance
// initializer..
long simpleInitTime = Init02.relTime();

//-------------------------------------------//

//Note that this constructor is physically
// located between the two instance initializer
// blocks. Both initializer blocks are
// executed before the constructor for this
// class is executed, but after the constructor
// for the superclass is executed.
B(String str){
//Invoke a parameterized constructor on the
// superclass.
super(str);
//Sleep for 100 msec before constructing
// this part of the object.
Init02.delay();
//Record the time and print a message showing
// the construction time for this part of
// the object.
bXstrTime = Init02.relTime();
System.out.println(str + "B: " + bXstrTime);
}//end constructor for B
//-------------------------------------------//

{//This is another instance initializer
//Sleep for 100 msec before doing this
// initialization.
Init02.delay();
//Record the time and print a message showing
// the time that this instance initializer
// was executed.
init2Time = Init02.relTime();
System.out.println("Initializer-2: " +
init2Time);
}//end instance initializer
//-------------------------------------------//

void showData(){
//This method displays the values that were
// saved in the instance variables during the
// five initialization steps, one of which
// was execution of the superclass
// constructor. The values are displayed
// in the order that the initialization steps
// occurred.
System.out.println(
"\nInitialization values:");
System.out.println("class A xstr: " +
aXstrTime);
System.out.println("class B init-1: " +
init1Time);
System.out.println("class B simple init: " +
simpleInitTime);
System.out.println("class B init-2: " +
init2Time);
System.out.println("class B xstr: " +
bXstrTime);
System.out.println();//blank line
}//end showData
}//end class B

Listing 15

Copyright 2003, Richard G. Baldwin.  Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.

About the author

Richard Baldwin is a college professor (at Austin Community College in Austin, Texas) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects, and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas.  He is the author of Baldwin's Programming Tutorials, which has gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

baldwin@DickBaldwin.com

-end-