Why Static Fields Are Not Initialized in Time

Why static fields are not initialized in time?

Because statics are initialized in the order they are given in source code.

Check this out:

class MyClass {
private static MyClass myClass = new MyClass();
private static MyClass myClass2 = new MyClass();
public MyClass() {
System.out.println(myClass);
System.out.println(myClass2);
}
}

That will print:

null
null
myClassObject
null

EDIT

Ok let's draw this out to be a bit more clear.

  1. Statics are initialized one by one in the order as declared in the source code.
  2. Since the first static is initialized before the rest, during its initialization the rest of the static fields are null or default values.
  3. During the initiation of the second static the first static is correct but the rest are still null or default.

Is that clear?

EDIT 2

As Varman pointed out the reference to itself will be null while it is being initialized. Which makes sense if you think about it.

When are static variables initialized?

From See Java Static Variable Methods:

  • It is a variable which belongs to the class and not to object(instance)
  • Static variables are initialized only once , at the start of the execution. These variables will be initialized first, before the initialization of any instance variables
  • A single copy to be shared by all instances of the class
  • A static variable can be accessed directly by the class name and doesn’t need any object.

Instance and class (static) variables are automatically initialized to standard default values if you fail to purposely initialize them. Although local variables are not automatically initialized, you cannot compile a program that fails to either initialize a local variable or assign a value to that local variable before it is used.

What the compiler actually does is to internally produce a single class initialization routine that combines all the static variable initializers and all of the static initializer blocks of code, in the order that they appear in the class declaration. This single initialization procedure is run automatically, one time only, when the class is first loaded.

In case of inner classes, they can not have static fields

An inner class is a nested class that is not explicitly or implicitly
declared static.

...

Inner classes may not declare static initializers (§8.7) or member interfaces...

Inner classes may not declare static members, unless they are constant variables...

See JLS 8.1.3 Inner Classes and Enclosing Instances

final fields in Java can be initialized separately from their declaration place this is however can not be applicable to static final fields. See the example below.

final class Demo
{
private final int x;
private static final int z; //must be initialized here.

static
{
z = 10; //It can be initialized here.
}

public Demo(int x)
{
this.x=x; //This is possible.
//z=15; compiler-error - can not assign a value to a final variable z
}
}

This is because there is just one copy of the static variables associated with the type, rather than one associated with each instance of the type as with instance variables and if we try to initialize z of type static final within the constructor, it will attempt to reinitialize the static final type field z because the constructor is run on each instantiation of the class that must not occur to static final fields.

Are there circumstances under which Java does not initialize static fields immediately?

Static variables are instantiated by the JVM classloader and are shared by every instance of the class.

public class StaticVars {

static int i = 3;

public static void main( String[] args ) {
System.out.println( "Called at Runtime: " + getStaticVar() );
System.out.println( "Called via it's static member: " + i );
}

static int getStaticVar() {
return i;
}

static {
int i = 1;
System.out.println( "JVM ClassLoaded: " + i );
}

static {
int i = 2;
System.out.println( "Second JVM ClassLoaded: " + i);
}

}

Further, as dognose and NPE referenced, if you attempt to reference a static variable before it is initialized you will get an Illegal Forward Reference Error as static fields are initialized in sequential order. The following restrictions apply to static fields static methods are not checked in the same manner.

8.3.2.3. Restrictions on the use of Fields during Initialization

  • The declaration of a member needs to appear textually before it is used only if the member is an instance (respectively static) field of a class or interface C and all of the following conditions hold:

  • The usage occurs in an instance (respectively static) variable initializer of C or in an instance (respectively static) initializer of C.

  • The usage is not on the left hand side of an assignment.

  • The usage is via a simple name.

  • C is the innermost class or interface enclosing the usage.

More Info :: Illegal forward reference error for static final fields

Why does a static variable initialized by a method call that returns another static variable remains null?

Static things gets executed in the order they appear in the code.

static String s1 = getVal();

So starting with first line, s1 gets evaluated and by that time s2 is still null. Hence you see the null value.

Why does java not initialise static nested class fields at the same time as static outter fields?

1) Is my understanding correct?

Basically yes. Consider what happens with your static member outerField :

public class OutterClass {

private static final OutterClass outterField = new OutterClass("outterField");

Theoretically, it's possible that the JVM could create that static final object when the program starts running, or when the class is loaded, but it doesn't. Instead, it'll only initialise it when needed - basically :

  • Instance of class is created, or
  • One of the Class's static fields or methods is accessed

(see https://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.1 )

So also with the static inner class. As you say, the JVM regards it as a top level inner class, so will only initialise its members when it also is needed.

2) Has this got anything to do with the JIT compiler or the class loader?

No and no. Initialisation of static members does not take place at class load time, but later (as we said, when the class is accessed). This is not a matter of compiler optimisation, but explicitly specified behaviour. After all, when you load a possibly-large class library, you would not want your JVM to consume memory or time initialising all the static members of classes that your program never touches; only-on-demand is a much better approach.

Is the InnerClass loaded when the OuterClass is loaded?

Yes (but not initialised then)

static Java field not initialized when a static method is called

There are two possible reasons:

  1. MyUtils.staticSchema returns null or
  2. AnotherClass is initialized during the initialization of MyClass due to a cyclic dependency.

I assume that you've already verified/ruled out option #1 so I'll focus on the second one:

Non-trivial static field initialization that depends on other classes can be problematic, because it can introduce long dependency chains and even dependency loops in class initialization.

If class A calls a method of class B during class initialization and class B calls a method of class A during class initialization, then there's a loop: that means that some code will see half-initialized classes.

If your MyClass somehow (directly or indirectly) touches AnotherClass during class initialization then it's quite possible tha the call to MyClass.getStaticSchema() is actually executed before schemaObj is initialized.

The best solution is to make the class initialization of any class depend on as few classes as possible.

Simple sample demonstrating the problem:

class A {
public static final String CONSTANT_IN_A = B.CONSTANT_IN_B;
public static final String ANOTHER_VALUE = "Value " + (Math.random() * 0 + 1);
}

class B {
public static final String CONSTANT_IN_B = "B version of " + A.ANOTHER_VALUE;
}

If you try to print A.CONSTANT_IN_A the output will be B version of null, because during the initialization of B.CONSTANT_IN_B the field ANOTHER_VALUE in A will not yet have been initialized.

Static fields in JVM loading

Generally, if there is some mismatch between the official specification and some article on the internet, you can safely assume that the specification has the last word and the article is wrong. This will serve you in 99.99% of all cases.

That’s especially true when it comes to the Java Virtual Machine, where articles notoriously mix up the steps of your question (“Loading, Linking, and Initializing”), and also regularly mix up formal steps and implementation details.

The article you’ve linked, does it wrong in several aspects:

  • Not every static final field is a compile-time constant. Only static final fields of primitive types or String are compile-time constants, if they are immediately initialized with a compile-time constant. Consider

    static final String CONSTANT1 = ""; // compile-time constant
    static final String CONSTANT2 = CONSTANT1; // compile-time constant
    // but
    static final String NO_CONSTANT1 = CONSTANT1.toString(); // not a constant expression
    static final String NO_CONSTANT2; // no initializer
    static {
    NO_CONSTANT2 = ""; // assignment in class initializer, valid, but not constant
    }
    static final BigInteger NO_CONSTANT3 = BigInteger.ONE; // neither primitive nor String
  • For compile time constants, every ordinary Java language read access is replaced by the constant value at compile-time, still, the identifiers exist and can be inspected via Reflection or accessed by byte code not generated from Java language source code. Whether the JVM treats constant fields specially, when it comes to their storage, is an implementation detail, but usually, implementors try to avoid special treatment, unless there’s a true benefit.

    The formal specification describes the constant variables as-if having a storage like any other variable, but of course, implementations may omit this, if they are capable of still retaining the mandated behavior (e.g. make the values available to Reflection).

    The initialization of both, constant and non-constant static variables is clearly specified as part of the Initialization (though not at the same time):

     


    1. Otherwise, record the fact that initialization of the Class object for C is in progress by the current thread, and release LC. Then, initialize each final static field of C with the constant value in its ConstantValue attribute (§4.7.2), in the order the fields appear in the ClassFile structure.

     9. Next, execute the class or interface initialization method of C.

    The “class or interface initialization method” is the method named <clinit> at the bytecode level, which contains all initializers of non-constant static fields as well as any code in static { … } blocks.

  • Class variables and the constant pool are different things. The constant pool contains the symbolic names of fields as well as values for compile-time constants (which, by the way, may include non-static fields as well).

    The values of the constant pool can be used to construct the actual runtime values, e.g. the byte sequence describing a string has to be converted to a reference to an actual String object and the primitive types may undergo Endianess conversions. When this processing happens as part of step 6 described in JVMS§5.5, as cited above, subsequent access to the field will consistently use the result of this process.

Static field is initialized later when the class has a static constructor

Can someone explain this behaviour? What can be the reason for this?

@JonSkeet has a paragraph in C# in Depth about static fields and static constructors. Here's a snippet:

The C# specification states:

  • The static constructor for a class executes at most once in a given
    application domain. The execution of a static constructor is triggered
    by the first of the following events to occur within an application
    domain:

    • An instance of the class is created.
    • Any of the static members of the
      class are referenced.

The CLI specification (ECMA 335) states in
section 8.9.5:

A type may have a type-initializer method, or not. A type may be
specified as having a relaxed semantic for its type-initializer method
(for convenience below, we call this relaxed semantic BeforeFieldInit):
.

  • If marked BeforeFieldInit then the type's initializer method is
    executed at, or sometime before, first access to any static field
    defined for that type
    .
  • If not marked BeforeFieldInit then that type's
    initializer method is executed ((at (i.e., is triggered by): first
    access to any static or instance field of that type, or first
    invocation of any static, instance or virtual method of that type))

This goes to show you that when a type doesn't have the beforefieldinit flag, the run-time may invoke it in an arbitrary time, given that it is before the first access to any static field defined, which is exactly what you're seeing.

Is there any other thing which can change when the static constructor
is called?

The only thing is creating a static type constructor on your type. Otherwises, you have no control over it's invocation.

So isn't the whole thing I described a little bit problematic?

Problematic in what regards? I see no problem as long as you know what you're in for. The CLI specification makes it absolutely clear as to what guarantees you have with a type initializer and without. Thus, if you follow those guidelines there should be no ambiguity.

Can static variable be initialized many times, because of class unloading?

That’s addressed in the specification in §12.7. Unloading of Classes and Interfaces:

An implementation of the Java programming language may unload classes.

A class or interface may be unloaded if and only if its defining class loader may be reclaimed by the garbage collector as discussed in §12.6.

Classes and interfaces loaded by the bootstrap loader may not be unloaded.

with the motivation for the rule directly connected to your question:

Class unloading is an optimization that helps reduce memory use. Obviously, the semantics of a program should not depend on whether and how a system chooses to implement an optimization such as class unloading. To do otherwise would compromise the portability of programs. Consequently, whether a class or interface has been unloaded or not should be transparent to a program.

Reloading may not be transparent if, for example, the class has static variables (whose state would be lost), static initializers (which may have side effects), or native methods (which may retain static state). Furthermore, the hash value of the Class object is dependent on its identity. Therefore it is, in general, impossible to reload a class or interface in a completely transparent manner.

Since we can never guarantee that unloading a class or interface whose loader is potentially reachable will not cause reloading, and reloading is never transparent, but unloading must be transparent, it follows that one must not unload a class or interface while its loader is potentially reachable. A similar line of reasoning can be used to deduce that classes and interfaces loaded by the bootstrap loader can never be unloaded.

Besides the explicitly mentioned bootstrap loader (which needed an explicit statement as it is represented by null, so reachability is meaningless), the application class loader, also known as system class loader is always reachable. The same applies to its parent, the extension class loader prior to JDK 9 and the platform class loader since then.

The implication is that for ordinary applications loaded by the application loader and all of its direct dependencies, class unloading simply is impossible. Only additional class loaders created by the application or a framework may become unreachable.

The specification cited above also says:

Class unloading is an optimization that is only significant for applications that load large numbers of classes and that stop using most of those classes after some time. A prime example of such an application is a web browser, but there are others. A characteristic of such applications is that they manage classes through explicit use of class loaders. As a result, the policy outlined above works well for them.

The example reflects the history of Java but today, a prime example would rather be an application server. When redeploying a new version or even when loading the same class files again with a new class loader, they’re technically different classes and the transparency of unloading is not relevant.

This is covered by the virtual machine specification, §5.3. Creation and Loading which states:

At run time, a class or interface is determined not by its name alone, but by a pair: its binary name (§4.2.1) and its defining class loader.


A special case are classes created via the new defineHiddenClass method. Since those classes can not get resolved through their defining loader by name, it’s possible to unload a hidden class as soon as no reference to it exists. It can’t get reloaded again. But you could use the same definition to create an arbitrary number of identical hidden classes, as they do not interfere.



Related Topics



Leave a reply



Submit