SCJP Study Guide:
Declarations, Initialization and Scoping


Printer-friendly version Printer-friendly version | Send this 
article to a friend Mail this to a friend


Previous Next vertical dots separating previous/next from contents/index/pdf Contents
XyzWs SCJP Study Guide: Initialization

Initialization

Object types in Java are very different from the primitive types. Simply declaring a variable whose type is given as a class does not automatically create an object of that class. Objects must be explicitly constructed.

Steps of constructing an object:

  • The Java virtual machine allocates enough unused memory in the heap that can be used to hold the object;
  • The Java virtual machine insures proper initialization of objects, for example, filling in the object's instance variables with predictable default values before it is used by any code.

As a developer, you may not care where in memory the object is stored, but you will usually want to exercise some control over what initial values are stored in a new object's instance variables. In many cases, you will also want to do more complicated initialization or bookkeeping every time an object is created.

The Java language has three mechanisms dedicated to ensuring proper initialization of objects: instance initializers (also called instance initialization blocks), instance variable initializers, and constructors. (Instance initializers and instance variable initializers collectively are called "initializers.") All three mechanisms result in Java code that is executed automatically when an object is created. When you allocate memory for a new object with the new operator or the newInstance() method of class Class, the Java virtual machine will insure that initialization code is run before you can use the newly-allocated memory. If you design your classes such that initializers and constructors always produce a valid state for newly-created objects, there will be no way for anyone to create and use an object that isn't properly initialized.

An instance variable of a class can be assigned an initial value in its declaration, just like any other variable. These initializations are executed whenever a new object is constructed. For initialization of class variables (static member variables), the situation is quite different. There is only one copy of a static variable, and initialization of that variable is executed just once, when the class is first loaded.

Default Initial Values

If you provide no explicit initialization to instance variables, they will be awarded predictable default initial values, which are based only on the type of the variable. Instance variables of numerical type (int, double, etc.) are automatically initialized to zero if you provide no other values; boolean variables are initialized to false; and char variables, to the Unicode character with code number zero. An instance variable can also be a variable of object type and the default initial value is null.

The following table shows the default initial values for each of the variable types. These are the default initial values for both instance and class variables. Local variables are not given default initial values. They must be initialized explicitly before they are used.

Type Default Value
boolean false
byte (byte) 0
short (short)0
int 0
long 0L
char \u0000
float 0.0f
double 0.0d
object reference null

If you don't explicitly initialize an instance variable, that variable will retain its default initial value when new returns its object reference.

For example, here is a class, named Program, whose var2 field is not explicitly initialized (there are no constructors or initializers in the class):

class Program {
    private int var1=10;
    private int var2;
}

As a result, when the reference to a new Program object is first returned by new, the var2 field will be its default initial value. Because var2 is an int, its default initial value is zero. But the var1 explicitly initialize to a value of 10, then when each Program object is created, var1 will, in effect, be initialized twice. First, var1 will be given its default initial value of zero. Later, the zero will be overwritten with the proper initial value of 10. All of this takes place while the Java virtual machine is creating the new object -- before it returns the reference to the new object. By the time the reference to a new Program object is returned from the new operator, the var1 field will be set to 10.

Constructors


The central player in object initialization is the constructor. Objects are created with the operator, new. For example, a program that wants to use a Program object could say:

Program obj;
obj = new Program();

In this example, "new Program()" is an expression that allocates memory for the object, initializes the object's instance variables, and then returns a reference to the object. This reference is the value of the expression, and that value is stored by the assignment statement in the variable, obj. Part of this expression, "Program()", looks like a subroutine call, and that is no accident. It is, in fact, a call to a special type of subroutine called a constructor. This might puzzle you, since there is no such subroutine in the class definition.

However, every class has a constructor. If the programmer doesn't provide one, then the system will provide a default constructor.

The default constructor does nothing beyond the basics: allocate memory and initialize instance variables. If you want more than that to happen when an object is created, you can include one or more constructors in the class definition.

In Java, constructors are similar to methods, but they are not methods. Like a method, a constructor has a set of parameters and a body of code. Unlike methods, however, constructors have no return type. Like methods, you can give access specifiers to constructors, but unlike methods, constructors with public, protected, or package access are not inherited by subclasses. (Also, instead of determining the ability to invoke a method, the access level of a constructor determines the ability to instantiate an object.)

Initializers

The body of a class declares members (fields and methods and nested classes and interfaces), initializers including instance initializers and static initializers, and constructors.

You can use initializers to assign an initial value to instance or static variables:

  • Instance initializers are blocks of executable code by curly braces that may be used to help initialize an instance when it is created.
  • Static initializers are blocks of executable code by curly braces that may be used to help initialize a class when it is first loaded.

The initializers are embedded in the body of a class. You can insert any number of initializers at any places (they may be separated by other code blocks) within your class definition.

In Java , when an object is created, initialization is done in this order:

  1. Set fields to default initial values (0, false, null)
  2. Call the constructor for the object (but don't execute the body of the constructor yet)
  3. Invoke the constructor of the superclass
  4. Initialize fields using initializers and initialization blocks
  5. Execute the body of the constructor

In what order they are executed?

"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." (Java in a Nutshell by David Flanagan)

Instance initializers and variable initializers, along with constructors, are executed each time a new object of the class is instantiated. But, the static initializers belonging to a class are executed one time only when the class is loaded.

Variable Initializers

Variable initializers are transformed into assignment statements, and these assignment statements are executed before the invocation of the class instance constructor-body. This ordering ensures that all instance fields are initialized by their variable initializers before any statements that have access to that instance are executed. For example,

class A 
{
  int x = 1; //Variable Initializer
  int y;
  public A() {
    System.out.printf("x = %d,  y = %d", x, y);
    y = x + 6;
  }
  public static void main(String[] args) {
    new A();
  }
}

The above code produced the following output:

x = 1, y = 0

The value of x is 1 because the variable initializer is executed before the class instance constructor-body is invoked. However, the value of y is 0 (the default value of an int) because the assignment to y is not executed until after the class constructor returns.

Let's look at another example:

class Super {
   Super() {
     printVariable("Super");
   }
   public void printVariable(String name) {}
}

class Sub extends Super 
{
   int x = 1;
   int y;
   Sub() {
	 printVariable("Sub");
   }
   public void printVariable(String name) {
	 System.out.printf("(%s) x = %d,  y = %d\n", name, x, y);
   }

   public static void main(String[] args) {
	   new Sub();
   }
}

The above code produced the following output:

(Super) x = 0,  y = 0
(Sub) x = 1,  y = 0

Instance Initializers

An instance initializer is a block of executable code by curly braces and used to help initialize instance when it is created. For example,

class Super {
   Super() {
     printVariable("Super");
   }
   public void printVariable(String name) {}
}

class Sub extends Super 
{
   int y;

   // The following block is an instance initializer
   {
     printVariable("Instance Initializer(1)");
     y = 10;
   }

   int x = 1; // Variable Initialzer
   Sub() {
	 printVariable("Sub");
   }
   public void printVariable(String name) {
	 System.out.printf("(%s) x = %d,  y = %d\n", name, x, y);
   }

   // The following block is an instance initializer separated by some methods
   {
     printVariable("Instance Initializer(2)");
     y = 30;
   }

   public static void main(String[] args) {
	   new Sub();
   }
}

The above code produced the following output:

(Super) x = 0,  y = 0
(Instance Initializer(1)) x = 0,  y = 0
(Instance Initializer(2)) x = 1,  y = 10
(Sub) x = 1,  y = 30

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. Let's take a look the procedure of running the above example code:

  1. Set x and y fields to their default value.
  2. Call the constructor Sub() for the new object (but don't execute the body of the constructor yet). The Java compiler create a implicit default constructor super() for it to call superclass default constructor.
  3. Invoke the constructor of the superclass Super() which prints out "(Super) x = 0, y = 0".
  4. The first instance initializer (Instance Initializer(1)) runs and prints out "(Instance Initializer(1)) x = 0, y = 0". At this point variable x's does not initialized to 1.
  5. The variable x runs its variable initializer. x has been set to 1.
  6. The second instance initializer block (Instance Initializer(2)) runs and prints out "(Instance Initializer(2)) x = 1, y = 10".
  7. Excute the constructor-body of Sub() which prints out "(Sub) x = 1, y = 30"

Static Initializers

Static initializers are blocks of executable code by curly braces and qualified by the keyword static that may be used to help initialize a class when it is first loaded. For example,

class Super {
   Super() {
     printVariable("Super");
   }
   public void printVariable(String name) {}
}

class Sub extends Super 
{
   int y;

   static {
     printVariableStatic("Static Initializer(1)");
     z = 10;
   }
   static int z = 1;
   static void printVariableStatic(String name) {
     System.out.printf("(%s) z = %d\n", name, z);
   }
   static {
     printVariableStatic("Static Initializer(2)");
     z = 10;
   }

   
   // The following block is an instance initializer
   {
     printVariable("Instance Initializer(1)");
     y = 10;
   }

   int x = 1; // Variable Initialzer
   Sub() {
     printVariable("Sub");
   }
   public void printVariable(String name) {
     System.out.printf("(%s) x = %d,  y = %d\n", name, x, y);
   }

   // The following block is an instance initializer separated by some methods
   {
     printVariable("Instance Initializer(2)");
     y = 30;
   }

   public static void main(String[] args) {
     new Sub();
   }
}

The above code produced the following output:

(Static Initializer(1)) z = 0
(Static Initializer(2)) z = 1
(Super) x = 0,  y = 0
(Instance Initializer(1)) x = 0,  y = 0
(Instance Initializer(2)) x = 1,  y = 10
(Sub) x = 1,  y = 30

According to the output result, all static variables and static initializer blocks are run first as in the same order as written in the source java program when the first time loading class. We can change the above code to show that the Static members are initialized when the first time class loaded. In the following code, we use the Class.forName() to load a class first, you will see that static initializers only run at the first time when class is loaded:

class Super {
   static {
     System.out.println("Static Initializer in Super class");
   }

   Super() {
     printVariable("Super");
   }
   public void printVariable(String name) {}
}

class Sub extends Super 
{
   int y;

   static {
     printVariableStatic("Static Initializer(1)");
     z = 10;
   }
   static int z = 1;
   static void printVariableStatic(String name) {
     System.out.printf("(%s) z = %d\n", name, z);
   }
   static {
     printVariableStatic("Static Initializer(2)");
     z = 10;
   }

   // The following block is an instance initializer
   {
     printVariable("Instance Initializer(1)");
     y = 10;
   }

   int x = 1; // Variable Initialzer
   Sub() {
     printVariable("Sub");
   }
   public void printVariable(String name) {
     System.out.printf("(%s) x = %d,  y = %d\n", name, x, y);
   }

   // The following block is an instance initializer separated by some methods
   {
     printVariable("Instance Initializer(2)");
     y = 30;
   }

   public static void main(String[] args) {
     try {
       Class c   = Class.forName("Sub");
     } catch (ClassNotFoundException e) {
       e.printStackTrace();
     } 
     System.out.println("Create a new Instance of Sub");
     new Sub();
   }
}

The above code produced the following output:

Static Initializer in Super class
(Static Initializer(1)) z = 0
(Static Initializer(2)) z = 1
Create a new Instance of Sub
(Super) x = 0,  y = 0
(Instance Initializer(1)) x = 0,  y = 0
(Instance Initializer(2)) x = 1,  y = 10
(Sub) x = 1,  y = 30

What Does Class.forName("X") Method Do? You can find it at our Java FAQ section.

Initializers Can't Make Forward References

When you write an initializer (either an instance variable initializer or instance initializer), you must be sure not to refer to any instance variables declared textually after the variable being initialized. In other words, you can't make a forward reference from an initializer. If you disobey this rule, the compiler will give you an error message and refuse to generate a class file. When an object is created, initializers are executed in textual order -- their order of appearance in the source code. This rule helps prevent initializers from using instance variables that have yet to be properly initialized.

 


Previous Next vertical dots separating previous/next from contents/index/pdf Contents

  |   |