Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

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

When a constant isn't really a constant

Cyclic class dependencies can create unpredictable runtime behavior

  • Print
  • Feedback

March 28, 2003

Q What are the possible negative effects of using cyclic definitions in Java?

A Normally, a Java compiler produces very "dynamic" output: you can recompile just a single class, and the rest of the application picks up the changes. This happens because the .class format uses dynamic links to reference cross-class constructs such as fields and methods, and they are resolved only at classloading time.

In this article, I describe a well-known exception to this behavior and an exception to the exception that is fairly rare but can cause very subtle and hard-to-see errors. Cyclic field definitions cause the latter exception, which leads to somewhat nondeterministic execution in Java.

Inlined static final constants

Consider the following two definitions:

public class Main implements InterfaceA
{
    public static void main (String [] args)
    {
        System.out.println (A);
    } 
} // End of class
public interface InterfaceA
{
    public static final int A = 1;
} // End of interface


According to the Java Language Specification, any static final field initialized with an expression that can be evaluated at compile time must be compiled to byte code that "inlines" the field value. That is, no dynamic link will be present inside class Main telling it to obtain the value for A from InterfaceA at runtime. Instead, the literal 1 will compile into Main.main() directly. You can confirm this by examining the javap dump for the method:

Method void main(java.lang.String[])
   0 getstatic #23 <Field java.io.PrintStream out>
   3 iconst_1
   4 invokevirtual #29 <Method void println(int)>
   7 return


The iconst_1 instruction above pushes integer value 1 to the JVM operand stack before invoking System.out.println() on it. The value is embedded into byte code, and no link to Interface.A remains. If you recompile InterfaceA.java so that field A is now, say, 2, but do not recompile Main.java, Main.main()'s output stays the same.

The above is well known to any experienced Java programmer. This slightly odd Java feature calls for extra attention when using any kind of Java make tool that can incrementally recompile Java sources based on file modification timestamps only (see Note 1). On the other hand, this feature is sometimes handy for implementing a poor man's version of conditional compilation in Java.

It looks like a constant but it isn't...

Note that for constant inlining to happen, several conditions must take place simultaneously. For example, it won't occur if the field initializer expression can be evaluated only at runtime:

public interface InterfaceA
{
    public static final int A = new java.util.Random ().nextInt ();
} // End of interface


With this change in InterfaceA, the byte code for Main.main() becomes:

Method void main(java.lang.String[])
   0 getstatic #27 <Field java.io.PrintStream out>
   3 getstatic #31 <Field int A>
   6 invokevirtual #37 <Method void println(int)>
   9 return


Observe the now dynamic reference to the field A value in the byte code.

The above change in Interface.A was quite conspicuous. However, imagine instead that the application uses the following three interfaces:

  • Print
  • Feedback

Resources