|
Tricks with Static Initializers
Don't be limited to simple expressions when initializing static values. Static initializers provide more complex processing for initializing classes
by Pete Ford
Posted April 15, 2003
The static initializer is a feature of Java that is very often not covered in-depth in books about Java. In fact, there are books about the language that don't even mention this feature of the language. For this reason, it's more than possible that even experienced Java developers reading this may not be aware of what static initializers are and how powerful they can be. When you declare static data in a class, you have the option of including an initial value, like this:
public static int fullCircle =
2.0 * Math.PI;
For simple initialization this is fine, but there are circumstances where this kind of initialization is not enough. For example, let's say that your application needs a preset table of sine values at one-degree intervals for all angles from 0 to 359 degrees. You could set the table up in a similar way:
public final static double[]
sine =
{
0.0,
0.01745240643728351,
0.03489949670250097,
// ...etc.
-0.01745240643728445
};
As you can see, setting up for all 360 values would become rather cumbersome and error-prone. Another disadvantage is that the compiled class file includes all of the preset values so that they can be used in the initialization; as a result, a class file containing just this array is over 7,500 bytes long.
An alternative is to use a static initializer, which is a block of code—rather like a static method—that is executed once only, when the class is loaded. It can't be called under any other circumstances, so it doesn't have a name, arguments, or any access modifiers, and does not return a value. For these reasons, all we need to declare a static initializer is the keyword "static" and the code enclosed in parentheses. In our example case we can use a static initializer like this:
public final static double[]
sine;
static
{
sine = new double[360];
for (int angle = 0 ;
angle < sine.length ;
angle++)
{
sine[angle] =
Math.sin((angle *
Math.PI)/180.0);
}
}
When the source for a class is compiled, the compiler generates code to initialize the class variables. This code is executed when the Java Virtual Machine (JVM) loads the class. A class can include one or more static initializers—for each of these the compiler generates the equivalent code and appends it to the class initialization code, and the initializers are executed in the order that they appear in the source. In this example, the compiler will allocate space for the array reference "sine." This code is followed by our initializer code from the static block, which will allocate space for 360 double values and then calculate and assign their values.
You may have noticed that the array "sine" is declared as final but is not initialized in its declaration; instead, the static initializer assigns a reference to the array when it is executed. This assignment is perfectly acceptable because the rules of Java are that any final static members must be initialized by the time the static initializers (if any) have been run. In other words, any final static values that do not have values assigned in their declarations must be assigned in a static initializer.
Back to top
|