Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 8 of 9
oid2.b = true oid2.by = 1 oid2.c = A oid2.d = 1.2 oid2.f = 3.4 oid2.i = 2 oid2.l = 3 oid2.s = 4 oid2.st = abc
What is responsible for executing the object field initializers? Would you believe that the constructor is? As strange as
it might seem, the compiler inserts byte code instructions into a class's constructor to execute object field initializers.
But there's more: When you look at a constructor from the JVM's perspective, you no longer see a constructor. Instead, you
see what the JVM refers to as an <init> method.
During class compilation, the compiler generates an <init> method for each of that class's constructors. If that class contains no constructors (as in ObjectInitializationDemo2), the compiler generates an <init> method that matches the default no-argument constructor. It is important to realize that each constructor has its own corresponding
<init> method and that the compiler places byte code instructions, apart from the instructions you specify (via Java source code),
into that method. Some of those instructions serve to execute object field initializers.
Take a close look at Listing 10. You cannot see its presence, but a constructor does exist. If you could see that constructor, it would probably look like the following code fragment:
ObjectInitializationDemo2 ()
{
}
That's right! The constructor would appear empty. Suppose you disassemble ObjectInitializationDemo2's class file. In that disassembly, you would encounter a no-argument <init> method that matches the default no-argument constructor. And what instructions would you find in that method? Take a look
at Listing 11:
Listing 11. ObjectInitializationDemo2's no-argument <init> method
0 aload_0 1 invokespecial java/lang/Object/<init>()V 4 aload_0 5 iconst_1 6 putfield ObjectInitializationDemo2/b Z 9 aload_0 10 iconst_1 11 putfield ObjectInitializationDemo2/by B 14 aload_0 15 bipush 65 17 putfield ObjectInitializationDemo2/c C 20 aload_0 21 ldc2_w #1.200000 24 putfield ObjectInitializationDemo2/d D 27 aload_0 28 ldc #3.400000 30 putfield ObjectInitializationDemo2/f F 33 aload_0 34 iconst_2 35 putfield ObjectInitializationDemo2/i I 38 aload_0 39 ldc2_w #3 42 putfield ObjectInitializationDemo2/l J 45 aload_0 46 iconst_4 47 putfield ObjectInitializationDemo2/s S 50 aload_0 51 ldc "abc" 53 putfield ObjectInitializationDemo2/st Ljava/lang/String; 56 return
Apart from Listing 11's byte code instructions executing ObjectInitializationDemo2's object field initializers, a close examination of Listing 11 reveals some interesting items about how Java works:
aload_0 instruction. That instruction pushes an address onto a stack. And what address does that instruction push? The current object
address -- as keyword this represents in source code. The invokespecial and putfield instructions pop that address from the stack and use the address to identify the proper object when making a call to an object
method or writing to an object field.
invokespecial java/lang/Object/<init>()V instruction. That instruction calls the default no-argument constructor -- to be precise, the default no-argument <init> method -- in the Object superclass. (Remember keyword super's use in calling a superclass constructor? You are seeing how Java uses that keyword at the byte code level.)
invokespecial java/lang/Object/<init>()V. It is no accident that the compiler places that instruction as the second instruction (after aload_0) in the default no-argument <init> method. In accordance with the way Java works, a constructor must first either call another constructor in the same class
or a constructor in its superclass. If a constructor does not explicitly call another constructor in the same class (via this) or a constructor in a superclass (via super), the compiler generates byte code instructions that are the equivalent of placing super (); at a constructor's start.
We will explore the second and third items in the above list later in this section, when we examine object initialization and class hierarchies. But first, we need to explore object field initializers and forward references, along with object block initializers.