Apart from constructors, object initialization mirrors class initialization. Instead of class field initializers, you have object field initializers. Furthermore, instead of class initialization blocks, you have object initialization blocks. You can also reference previously declared and initialized object fields but you cannot reference subsequently declared and initialized object fields. All of these concepts are demonstrated in Listing 8.
Listing 8. How object initialization mirrors class initialization
class Mirror
{
int x = 2;
int y = x;
{
System.out.println("x = " + x);
System.out.println("y = " + y);
}
public static void main(String[] args)
{
Mirror mirror = new Mirror();
}
}
Listing 8 reveals that an object initialization block is a block of statements introduced into the class body. Unlike a class initialization block, an object initialization block isn't prefixed by anything. Because you can initialize an object in a constructor, about the only good use for an object initialization block is in the context of an anonymous class, which doesn't have a constructor and which I'll discuss in a future article.
Compile Listing 8 (javac Mirror.java
) and run the resulting application (java Mirror
). You'll discover the following output:
x = 2
y = 2
Combining constructors and object field initializers and object initialization blocks
You can combine multiple constructors, object field initializers, and object initialization blocks in an application. Listing 9 provides an example.
Listing 9. A strange way to do object initialization
class MCOFIOIB
{
MCOFIOIB()
{
System.out.println("MCOFIOIB() called");
}
int x = 5;
{
x += 6;
}
int i;
MCOFIOIB(int i)
{
this.i = i;
System.out.println("MCOFIOIB(i) called: i = " + i);
}
{
System.out.println("i = " + i);
System.out.println("x = " + x);
}
public static void main(String[] args)
{
new MCOFIOIB();
System.out.println();
new MCOFIOIB(6);
}
}
Listing 9 declares a pair of constructors (MCOFIOIB()
and MCOFIOIB(int i)
), a pair of object fields (x
and i
), and a pair of object initialization blocks. Compile this listing as follows:
javac MCOFIOIB.java
Then run the resulting application:
java MCOFIOIB
You should observe the following output:
i = 0
x = 11
MCOFIOIB() called
i = 0
x = 11
MCOFIOIB(i) called: i = 6
This output is from the creation of two MCOFIOIB
objects. The first part originates from new MCOFIOIB();
and the second part originates from new MCOFIOIB(6);
. Each part reveals that object field initializers and object initialization blocks execute before a constructor executes. Furthermore, it reveals that object field initializers and object initialization blocks execute in top-down order. (x
had to be initialized to 11
before x = 11
could be output.)
<init>() methods
If you were to examine the bytecode that the compiler generates for MCOFIOIB.class
, you would observe the presence of <init>()
methods instead of constructors. The JVM invokes these methods instead of constructors.
You would also observe the following partial disassembly of the x
and i
fields:
Field #1
0000026d Access Flags
0000026f Name x
00000271 Descriptor I
00000273 Attributes Count 0
Field #2
00000275 Access Flags
00000277 Name i
00000279 Descriptor I
0000027b Attributes Count 0
Next, you would observe the following information and bytecode sequence for the MCOFIOIB()
constructor:
0 aload_0
1 invokespecial java/lang/Object/()V
4 aload_0
5 iconst_5
6 putfield MCOFIOIB/x I
9 aload_0
10 dup
11 getfield MCOFIOIB/x I
14 bipush 6
16 iadd
17 putfield MCOFIOIB/x I
20 getstatic java/lang/System/out Ljava/io/PrintStream;
23 new java/lang/StringBuilder
26 dup
27 invokespecial java/lang/StringBuilder/()V
30 ldc "i = "
32 invokevirtual java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;
35 aload_0
36 getfield MCOFIOIB/i I
39 invokevirtual java/lang/StringBuilder/append(I)Ljava/lang/StringBuilder;
42 invokevirtual java/lang/StringBuilder/toString()Ljava/lang/String;
45 invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
48 getstatic java/lang/System/out Ljava/io/PrintStream;
51 new java/lang/StringBuilder
54 dup
55 invokespecial java/lang/StringBuilder/()V
58 ldc "x = "
60 invokevirtual java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;
63 aload_0
64 getfield MCOFIOIB/x I
67 invokevirtual java/lang/StringBuilder/append(I)Ljava/lang/StringBuilder;
70 invokevirtual java/lang/StringBuilder/toString()Ljava/lang/String;
73 invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
76 getstatic java/lang/System/out Ljava/io/PrintStream;
79 ldc "MCOFIOIB() called"
81 invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
84 return
The instruction sequence from offset 0 through offset 1 is equivalent to invoking the Object
superclass's no-argument constructor:
new Object();
The instruction sequence from offset 4 through offset 17 is equivalent to the following class initialization block:
int x = 5;
{
x += 6;
}
The instruction sequence from offset 20 through offset 73 executes the second object initialization block:
{
System.out.println("i = " + i);
System.out.println("x = " + x);
}
The instruction sequence from offset 76 through offset 84 executes the MCOFIOIB()
constructor code and returns execution to the constructor's caller.
Again, don't worry about what the bytecode means. The important thing to remember is the initialization order. When you call MCOFIOIB()
, the following tasks are performed:
- The superclass's noargument constructor is invoked first.
- Object field initializers and object initialization blocks are then executed in top-down order.
- The constructor's code is executed last.
For brevity, I won't present the bytecode sequence for the MCOFIOIB(int i)
constructor; it's very similar to MCOFIOIB()
. The only difference is that the final code to be executed is MCOFIOIB(int i)
's code and not MCOFIOIB()
's code.
Conclusion
In this Java tutorial you've learned how to use class field initializers and class initialization blocks to initialize classes, and how to use constructors, object field initializers, and object initialization blocks to initialize objects. While relatively simple, class and object initialization is vital: the JVM must initialize classes and objects before they are used.
Now that you know how initialization works, you've largely completed your exploration of Java's class and object language features. The next tutorial in this series dips into interfaces, a slightly more advanced topic for beginning Java developers.
This story, "Class and object initialization in Java" was originally published by JavaWorld.