Member initialization | CodeGuru

Member initialization

Bruce Eckel’s Thinking in Java Contents | Prev | Next Java goes out of its way to guarantee that any variable is properly initialized before it is used. In the case of variables that are defined locally to a method, this guarantee comes in the form of a compile-time error. So if you say: void […]

Written By
CodeGuru Staff
CodeGuru Staff
Mar 1, 2001
6 minute read
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

Java


goes out of its way to guarantee that any variable is properly initialized


before it is used. In the case of variables that are defined locally to a


method, this guarantee comes in the form of a compile-time error. So if you say:

  void f() {
    int i;
    i++;
  }

You’ll


get an error message that says that


i

might not have been initialized. Of course, the compiler could have given


i

a default value, but it’s more likely that this is a programmer error and


a default value would have covered that up. Forcing the programmer to provide


an initialization value is more likely to catch a bug

.

If


a

primitive
is a data member of a class, however, things are a bit different. Since any
method can initialize or use that data, it might not be practical to force the
user to initialize it to its appropriate value before the data is used.
However, it’s unsafe to leave it with a garbage value, so each primitive
data member of a class is guaranteed to get an initial value. Those values can
be seen here:
//: InitialValues.java
// Shows default initial values
 
class Measurement {
  boolean t;
  char c;
  byte b;
  short s;
  int i;
  long l;
  float f;
  double d;
  void print() {
    System.out.println(
      "Data type      Inital valuen" +
      "boolean        " + t + "n" +
      "char           " + c + "n" +
      "byte           " + b + "n" +
      "short          " + s + "n" +
      "int            " + i + "n" +
      "long           " + l + "n" +
      "float          " + f + "n" +
      "double         " + d);
  }
}
 
public class InitialValues {
  public static void main(String[] args) {
    Measurement d = new Measurement();
    d.print();
    /* In this case you could also say:
    new Measurement().print();
    */
  }
} ///:~ 

The


output of this program is:

Data type      Inital value
boolean        false
char
byte           0
short          0
int            0
long           0
float          0.0
double         0.0

The


char

value is a null, which doesn’t print.

You’ll


see later that when you define an object handle inside a class without


initializing it to a new object, that handle is given a value of null.

You


can see that even though the values are not specified, they automatically get


initialized. So at least there’s no threat of working with uninitialized


variables.


Specifying
initialization

What


happens if you want to give a variable an initial value? One direct way to do


this is simply to assign the value at the point you define the variable in the


class. (Notice you cannot do this in C++, although C++ novices always try.)


Here the field definitions in class


Measurement

are changed to provide initial values:

class Measurement {
  boolean b = true;
  char c = 'x';
  byte B = 47;
  short s = 0xff;
  int i = 999;
  long l = 1;
  float f = 3.14f;
  double d = 3.14159; <p><tt>  //. . . </tt></p>

You


can also initialize non-primitive objects in this same way. If


Depth

is a class, you can insert a variable and initialize it like so:

class Measurement {
  Depth o = new Depth();
  boolean b = true; <p><tt>  // . . . </tt></p>

If


you haven’t given


o

an initial value and you go ahead and try to use it anyway, you’ll get a


run-time error called an


exception

(covered in Chapter 9).

You


can even call a method to provide an initialization value:

class CInit {
  int i = f();
  //...
}

This


method can have arguments, of course, but those arguments cannot be other class


members that haven’t been initialized yet. Thus, you can do this:

class CInit {
  int i = f();
  int j = g(i);
  //...
}

But


you cannot do this:

class CInit {
  int j = g(i);
  int i = f();
  //...
}

This


is one place in which the compiler, appropriately,


does

complain about

forward
referencing, since this has to do with the order of initialization and not the
way the program is compiled.

This


approach to initialization is simple and straightforward. It has the limitation


that


every

object of type


Measurement

will get these same initialization values. Sometimes this is exactly what you


need, but at other times you need more flexibility.


Constructor
initialization

The


constructor can be used to perform initialization, and this gives you greater


flexibility in your programming since you can call methods and perform actions


at run time to determine the initial values. There’s one thing to keep in


mind, however: you aren’t precluding the automatic initialization, which


happens before the constructor is entered. So, for example, if you say:

class
Counter {


int i;


Counter() { i = 7; }


// . . .

then


i

will


first be initialized to zero, then to 7. This is true with all the primitive


types and with object handles, including those that are given explicit


initialization at the point of definition. For this reason, the compiler


doesn’t try to force you to initialize elements in the constructor at any


particular place, or before they are used – initialization is already


guaranteed.


[21]


Order
of initialization

Within


a class, the order of initialization is determined by the order that the


variables are defined within the class. Even if the variable definitions are


scattered throughout in between method definitions, the variables are


initialized before any methods can be called – even the constructor. For


example:

//: OrderOfInitialization.java
// Demonstrates initialization order.
 
// When the constructor is called, to create a
// Tag object, you'll see a message:
class Tag {
  Tag(int marker) {
    System.out.println("Tag(" + marker + ")");
  }
}
 
class Card {
  Tag t1 = new Tag(1); // Before constructor
  Card() {
    // Indicate we're in the constructor:
    System.out.println("Card()");
    t3 = new Tag(33); // Re-initialize t3
  }
  Tag t2 = new Tag(2); // After constructor
  void f() {
    System.out.println("f()");
  }
  Tag t3 = new Tag(3); // At end
}
 
public class OrderOfInitialization {
  public static void main(String[] args) {
    Card t = new Card();
    t.f(); // Shows that construction is done
  }
} ///:~ 

In


Card

,


the definitions of the


Tag

objects are intentionally scattered about to prove that they’ll all get


initialized before the constructor is entered or anything else can happen. In


addition,


t3

is re-initialized inside the constructor. The output is:

Tag(1)
Tag(2)
Tag(3)
Card()
Tag(33)
f()

Thus,


the


t3

handle gets initialized twice, once before and once during the constructor


call. (The first object is dropped, so it can be garbage-collected later.) This


might not seem efficient at first, but it guarantees proper initialization


– what would happen if an overloaded constructor were defined that did


not

initialize


t3

and there wasn’t a “default” initialization for


t3

in its definition?


Static
data initialization

When


the

data
is
static
the same thing happens; if it’s a primitive and you don’t
initialize it, it gets the standard primitive initial values. If it’s a
handle to an object, it’s null unless you create a new object and attach
your handle to it.

If


you want to place initialization at the point of definition, it looks the same


as for non-statics. But since there’s only a single piece of storage for a


static

,


regardless of how many objects are created the question of when that storage


gets initialized arises. An example makes this question clear:

//: StaticInitialization.java
// Specifying initial values in a
// class definition.
 
class Bowl {
  Bowl(int marker) {
    System.out.println("Bowl(" + marker + ")");
  }
  void f(int marker) {
    System.out.println("f(" + marker + ")");
  }
}
 
class Table {
  static Bowl b1 = new Bowl(1);
  Table() {
    System.out.println("Table()");
    b2.f(1);
  }
  void f2(int marker) {
    System.out.println("f2(" + marker + ")");
  }
  static Bowl b2 = new Bowl(2);
}
 
class Cupboard {
  Bowl b3 = new Bowl(3);
  static Bowl b4 = new Bowl(4);
  Cupboard() {
    System.out.println("Cupboard()");
    b4.f(2);
  }
  void f3(int marker) {
    System.out.println("f3(" + marker + ")");
  }
  static Bowl b5 = new Bowl(5);
}
 
public class StaticInitialization {
  public static void main(String[] args) {
    System.out.println(
      "Creating new Cupboard() in main");
    new Cupboard();
    System.out.println(
      "Creating new Cupboard() in main");
    new Cupboard();
    t2.f2(1);
    t3.f3(1);
  }
  static Table t2 = new Table();
  static Cupboard t3 = new Cupboard();
} ///:~ 
Bowl

allows you to view the creation of a class, and


Table

and


Cupboard

create


static

members of


Bowl

scattered through their class definitions. Note that


Cupboard

creates a non-


static
Bowl
b3

prior to the


static

definitions. The output shows what happens:

Bowl(1)
Bowl(2)
Table()
f(1)
Bowl(4)
Bowl(5)
Bowl(3)
Cupboard()
f(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f(2)
f2(1)
f3(1)

The


static

initialization occurs only if it’s necessary. If you don’t create a


Table

object


and you never refer to


Table.b1

or


Table.b2

,


the


static
Bowl b1

and


b2

will


never be created. However, they are created only when the


first
Table

object


is created (or the first


static

access occurs). After that, the


static

object is not re-initialized.

The


order of initialization is


static

s


first, if they haven’t already been initialized by a previous object


creation, and then the non-


static

objects. You can see the evidence of this in the output.

It’s


helpful to summarize the

process
of creating an object. Consider a class called
Dog:
  1. The
    first time an object of type
    Dog
    is created,
    or
    the first time a
    static
    method or
    static
    field
    of class
    Dog
    is accessed, the Java interpreter must locate
    Dog.class,
    which it does by searching through the classpath.
  2. As
    Dog.class
    is loaded (which creates a
    Class
    object, which you’ll learn about later), all of its
    static
    initializers are run. Thus,
    static
    initialization
    takes place only once, as the
    Class
    object is loaded for the first time.
  3. When
    you create a
    new
    Dog( )
    ,
    the construction process for a
    Dog
    object first allocates enough storage for a
    Dog
    object on the heap.
  4. This
    storage is wiped to zero, automatically setting all the primitives in
    Dog
    to their default values (zero for numbers and the equivalent for
    boolean
    and
    char).
  5. Any
    initializations that occur at the point of field definition are executed.
  6. Constructors
    are executed. As you shall see in Chapter 6, this might actually involve a fair
    amount of activity, especially when inheritance is involved.


Explicit
static initialization

Java


allows you to group other


static

initializations inside a special “

static
construction clause” (sometimes called a
static
block
)
in
a class. It looks like this:
class
Spoon {


static int i;


static {


i = 47;


}


// . . .

So


it looks like a method, but it’s just the


static

keyword followed by a method body. This code, like the other


static

initialization, is executed only once, the first time you make an object of


that class


or

you access a


static

member of that class (even if you never make an object of that class). For


example:

//: ExplicitStatic.java
// Explicit static initialization
// with the "static" clause.
 
class Cup {
  Cup(int marker) {
    System.out.println("Cup(" + marker + ")");
  }
  void f(int marker) {
    System.out.println("f(" + marker + ")");
  }
}
 
class Cups {
  static Cup c1;
  static Cup c2;
  static {
    c1 = new Cup(1);
    c2 = new Cup(2);
  }
  Cups() {
    System.out.println("Cups()");
  }
}
 
public class ExplicitStatic {
  public static void main(String[] args) {
    System.out.println("Inside main()");
    Cups.c1.f(99);  // (1)
  }
  static Cups x = new Cups();  // (2)
  static Cups y = new Cups();  // (2)  <p><tt>} ///:~ </tt></p>

The


static

initializers for


Cups

will be run when either the access of the


static

object


c1

occurs on the line marked (1), or if line (1) is commented out and the lines


marked (2) are uncommented. If both (1) and (2) are commented out, the


static

initialization for


Cups

never occurs.


Non-static
instance initialization

Java


1.1


provides a similar syntax for initializing non-static variables for each
object. Here’s an example:
//: Mugs.java
// Java 1.1 "Instance Initialization"
 
class Mug {
  Mug(int marker) {
    System.out.println("Mug(" + marker + ")");
  }
  void f(int marker) {
    System.out.println("f(" + marker + ")");
  }
}
 
public class Mugs {
  Mug c1;
  Mug c2;
  {
    c1 = new Mug(1);
    c2 = new Mug(2);
    System.out.println("c1 &amp; c2 initialized");
  }
  Mugs() {
    System.out.println("Mugs()");
  }
  public static void main(String[] args) {
    System.out.println("Inside main()");
    Mugs x = new Mugs();
  }
} ///:~ 

You


can see that the instance initialization clause:

  {
    c1 = new Mug(1);
    c2 = new Mug(2);
    System.out.println("c1 &amp; c2 initialized");
  }

looks


exactly like the static initialization clause except for the missing


static

keyword. This syntax is necessary to support the initialization of


anonymous
inner classes

(see Chapter 7).



[21]

In contrast, C++ has the


constructor
initializer list

that causes initialization to occur before entering the constructor body, and


is enforced for objects. See


Thinking
in C++

.

Contents

|

Prev

|

Next
CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.