views:

219

answers:

8

Our application is using initialization code that depends on the order static code is executed and I'm wondering if this order will be consistent across all JVMs.

Here is a sample of what I mean:


public class Main {

    static String staticVar = "init_value";

    public static void main(String[] args) {

        System.out.println(A.staticVar);
        staticVar = "mainValue";
        System.out.println(A.staticVar);
    }
}

public class A {
    static String staticVar = Main.staticVar;
}

will give:

init_value
init_value

and


public class Main {

    static String staticVar = "init_value";

    public static void main(String[] args) {

        // System.out.println(A.staticVar);
        staticVar = "mainValue";
        System.out.println(A.staticVar);
    }
}

public class A {
    static String staticVar = Main.staticVar;
}

will give (on my environment):

mainValue

To summarize, across all JVMs, is static code always executed when we use a class for the first time?

+13  A: 

EDIT: Despite all the reassurances below, if you're thinking of relying on this sort of thing, I would try hard to refactor your code so that it doesn't crop up. While it is guaranteed to work, it's also likely to make your code very brittle. The fact that static initializers get called "invisibly" makes them relatively hard to reason about and debug.


Yes, this is guaranteed by the language specification. From section 8.7 of the spec:

Any static initializers declared in a class are executed when the class is initialized and, together with any field initializers (§8.3.2) for class variables, may be used to initialize the class variables of the class (§12.4).

StaticInitializer: static Block

It is a compile-time error for a static initializer to be able to complete abruptly (§14.1, §15.6) with a checked exception (§11.2). It is a compile-time error if a static initializer cannot complete normally (§14.21).

The static initializers and class variable initializers are executed in textual order.

And from section 12.4:

Initialization of a class consists of executing its static initializers and the initializers for static fields declared in the class. Initialization of an interface consists of executing the initializers for fields declared in the interface.

Before a class is initialized, its direct superclass must be initialized, but interfaces implemented by the class need not be initialized. Similarly, the superinterfaces of an interface need not be initialized before the interface is initialized.

A class or interface type T will be initialized immediately before the first occurrence of any one of the following:

  • T is a class and an instance of T is created.
  • T is a class and a static method declared by T is invoked.
  • A static field declared by T is assigned.
  • A static field declared by T is used and the field is not a constant variable (§4.12.4).
  • T is a top-level class, and an assert statement (§14.10) lexically nested
Jon Skeet
How is it that accepted answer is always coming from Jon? ;) Looks like he has some kind of unfair advantage on this site ;)
eugener
+3  A: 

Static initialisers (e.g. your staticVar declarations) are always executed when you use a class for the first time.

Static methods are only executed when they are called. In your case, this is happening because the static void main(String[] args) is the entry point to your application. But if you defined a different static method then it would not be called.

It is also possible to create a static initialiser block that will also be called automatically before the class is first used, e.g.

static {
  // some initialisation code here
}
mikera
+3  A: 

That should be all the same on all platforms. See JVM Specification : http://java.sun.com/docs/books/jvms/second_edition/html/Concepts.doc.html#19075

PeterMmm
A: 

Yes, I believe that would be the point by definition.

Trefex
A: 

Static Block will always run first not just the first time... Before executing any code block, JVM execute the static code block first, and then only it run the code block as it has been designed...

venJava
+2  A: 

A quote from Java specification:

Initialization of a class consists of executing its static initializers and the initializers for static fields declared in the class. Initialization of an interface consists of executing the initializers for fields declared in the interface.

eugener
+1  A: 

Yes, according to the Java Language Specification static code is always executed in the same order on all (compliant) JVM's.

8.7 Static Initializers

The static initializers and class variable initializers are executed in textual order.

Chadwick
That shows the order within the static initializers - but it doesn't answer as to whether the code is always executed when a class is used.
Jon Skeet
+1  A: 

Dittos to other posters, but let me add that a static initializer that depends on the state of other classes like in your example seems to me to make for very fragile and difficult-to-maintain code. I'll use static intializers to populate internal class data -- to fill up an array with default values or that sort of thing. But I don't think I've ever had one peek at the data in another class. Technically legal, and maybe there are odd cases where it's a good idea, but yuck.

Jay
+1 for yuck... IMO such an initializer is (only) a good idea to see/show when it is called.
Carlos Heuberger