28 August 2005

Static Initializers

An extremely powerful feature

Here is a very simple class:

public class Sample
{
public static int x = 6;
}


This is straightforward enough - any code that reads Sample.x will get the correct value. The question is, where is the value of x actually set?

The answer is that the Java compiler generates code to initialize the static data, and this code is included in the resulting class file. The JVM executes this code as soon as the class has been loaded into memory. In the case of our Sample class, the first reference to the class causes the JVM to locate the class file, load it into memory then run the initialization code. All of the initialization code for a given class is encapsulated into a single "method", called the static initializer.

Static initializers do not have names, arguments, or access modifiers and do not return any values - in other words, you can't call static initializers as if they were methods. A class's static initializer is run once and once only during the lifetime of an application, at the point where the class is loaded.

If initializing data fields were all that static initializers did, they wouldn't be particularly interesting. What makes them far more powerful is that you can write your own code to be added to the static initializers of your own classes. Here is an example:

public class Sample2
{
public final static Properties props;
static
{
props = new Properties();
try
{
InputStream is = new FileInputStream(
"my.properties");
props.load(is);
is.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}


The first thing to note is the static keyword followed by a block of code - this is how we tell the compiler that the code is to be added to the static initializer. In this case loading the class causes it to load the Properties object from a file.

Some other things to know about static initializers: first, you can include as many static{...} sections as you like in a class source; each section of compiled code is added to the static initializer in the order the static blocks appear in the source. Second, static initializer code can throw only uncaught exceptions (hence the try/catch block in the example). Third, note that any final static data must be initialized; in the example the final props field isn't initialized at the point where it's declared, which would normally be an error, but it's assigned in our static initializer so the compiler doesn't complain.

You can put pretty much any code you like into static initializers - this simple fact makes them surprisingly powerful.

For example, if you've ever used JDBC you may have wondered how it manages to select the correct driver for a given database URL when there is more than one driver loaded. The trick is that all JDBC drivers' static initializers include code that creates an instance of the driver and then passes this object to a static method in the DriverManager class, which adds the driver to an internal list; when your application passes a URL string to DriverManager.getConnection(), that method iterates through the list of drivers and passes the URL to each driver in turn, until one of them recognizes the URL format and opens and returns a database connection.

Another example is Log4J, whose Logger class has a static initializer that by default scans the directories in the classpath looking for a file named "log4j.xml" or "log4j.properties". If it finds such a file it reads the logging configuration from it. This means that you don't need to write a single line of configuration code - the configuration can be completely defined in a file, and this will be loaded automatically the first time your application references the Logger. Velocity - a templating package from the Apache Jakarta project - uses a similar technique to load its default configuration settings.

I leave it to you, adventurous reader, to think of more applications for static initializers.

Considering that static initializers are so powerful and also that it would be impossible to understand some commonly-used packages without having an understanding of them, it is strange and surprising that there are a number of (otherwise excellent) books about Java programming that that make no mention of them whatsoever. My recommendation, when choosing a book, is to check the index for mention of static initializers; if there's no reference, move on to the next book.

Labels:

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]



<< Home