Static Initialization in the BlackBerry JVM

The Problem

I was investigating some odd behavior on the BlackBerry recently to try to diagnose a problem. Along the way, I discovered a bug in BlackBerry’s JVM, as a result of which static initialization can occur multiple times – and even static final variables can change.

Consider the following code:

public class App extends Application
{
	public static void main(String[] args)
	{
		System.out.println(BaseClass.class.getName());
		System.out.println(Subclass.class.getName());
	}
}

public class BaseClass
{
	static
	{
		System.out.println("Static initialization called");
	}
}

public class Subclass extends BaseClass
{

}


Under the rules of Java (specifically section 12.4.2), this should print out:

Static initialization called
BaseClass
Subclass

Under RIM’s implementation, however, it prints out:

Static initialization called
BaseClass
Static initialization called
Subclass

Apparently when a subclass is loaded, it does static initialization for both the subclass and superclass, even if the superclass has already been loaded

Why is this a problem?

This means that you cannot assume that static final variables will remain the same. For example, consider the following:

public class App extends UiApplication
{
	public static void main(String[] args)
	{
		try
		{
			System.out.println("START: " + BaseClass.obj);
			Thread.sleep(100);

			System.out.println(Subclass.class.getName() + " loaded");
			System.out.println("AFTER: " + BaseClass.obj);
		}
		catch(InterruptedException ex)
		{
		}
	}
}
public class BaseClass
{
	public static final long obj = System.currentTimeMillis();
}
public class Subclass extends BaseClass
{
}

On the BlackBerry this would print out something along the lines of:

START: 1278618140120
Subclass loaded
AFTER: 1278618140235

Here the static final variable in BaseClass will be changed halfway through the program! That means that unless you can guarantee that a class has no subclasses, you have to assume that your static variables might reinitialize to different objects unexpectedly, until you are certain that all subclasses have been loaded. This is particularly problematic for static object references, where you might need to refer to the static object at different points in the program, but can no longer assume that you will always be referencing the same object.

A solution

This alternative syntax for the base class seems to make static object references work as expected, but it means that you can’t use the final keyword with your static variables anymore.

public class BaseClass
{
	private static Object obj; //Since the variable isn't final anymore, I made it private

	static
	{
		if (obj == null)
			obj = new Long(System.currentTimeMillis()); //or however you want to initialize the variable
	}

	public static Object getObj()
	{
		return obj;
	}
}

For primitives, you may have to wrap the primitive in its associated wrapper class, and use the above syntax with object references instead of using static primitives.

Related posts: