System.out is declared as static final and initialized with null? [duplicate]

When I was going through the System.class I found something which seemed strange to me. When you look at declaration of System.in, System.out, System.err these are decalred as final static but also initialized with null

public final static InputStream in = null;  
public final static PrintStream out = null;  
public final static PrintStream err = null;

Since final can be initialized only once then how these are getting managed ?
When we use System.out.print("..."); It is obvious that out is not null but being a final static how it is not null ?

So can any one explain that how out is initialized which is already declared final ?


Solution 1:

It is initialized with native code in a static initializer. At the top of System.java you have:

/* register the natives via the static initializer.
 *
 * VM will invoke the initializeSystemClass method to complete
 * the initialization for this class separated from clinit.
 * Note that to use properties set by the VM, see the constraints
 * described in the initializeSystemClass method.
 */
private static native void registerNatives();
static {
    registerNatives();
}

The registerNatives() method will initialize in/out/err - and it's doing so in native code - native code can pretty much do whatever it want and are not limited to all of the java language rules. (Though you could get around setting an already initialized final field in Java via reflection too)

Solution 2:

Since final can be initialized only once then how these are getting managed ?

While you can change static final variable via reflection, in this case the fields are changed via native methods.

From java.lang.System

public static void setIn(InputStream in) {
    checkIO();
    setIn0(in);
}

// same for setOut(), setErr()

private static native void setIn0(InputStream in);
private static native void setOut0(PrintStream out);
private static native void setErr0(PrintStream err);

When we use System.out.print("..."); It is obvious that out is not null but being a final static how it is not null ?

It gets set before you have a chance to use it.

You might wonder why it does this? The answer is almost certainly related to the order classes are loaded. Many of the classes startup in order but they need to be initialised in an order which works.

So can any one explain that how out is initialized which is already declared final ?

This is because final isn't as final as you might think. It has been suggested we need a final final.