PrintStream object out is initialized by null, how we call method on it?
Asked Answered
B

4

11

I have seen in the System class that the out object (of type PrintStream) is initialized with a null value. How can we call method like System.out.prinln("");? In System class out variable initialized like this way:

package java.lang;

public final class System {
    public final static PrintStream out = nullPrintStream();

     private static PrintStream nullPrintStream() throws NullPointerException {
        if (currentTimeMillis() > 0) {
            return null;
        }
        throw new NullPointerException();
     }
}

As per shown above code out variable initialized by null and this variable is final, so it can not initialized further then how can we use "out" variable.

Bucentaur answered 1/8, 2013 at 8:49 Comment(1)
may be help you https://mcmap.net/q/605489/-out-in-system-out-printlnTerce
J
8

JVM calls the private static void initializeSystemClass() method which initializes it.

See these two lines of code :

setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true));
setErr0(new PrintStream(new BufferedOutputStream(fdErr, 128), true));

These are the two native methods :

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

There is a nice article on it.

Josephinajosephine answered 1/8, 2013 at 8:54 Comment(2)
The article doesn't explain the currentTimeMillis trick. Why is it used? To avoid some kind of optimisation?Tankoos
@kan: it’s funny (or sometimes rather frightening) to see such esoteric code even in fundamental Java classes. The nullInputStream() counterpart has a comment talking about prohibiting inlining, but null never gets inlined at compile-time and the way you get to the null will be irrelevant at runtime. Consequently, the Java 7 version doesn’t have that strange method anymore.Election
E
9

The explanation is in the comments:

/**
 * The following two methods exist because in, out, and err must be
 * initialized to null.  The compiler, however, cannot be permitted to
 * inline access to them, since they are later set to more sensible values
 * by initializeSystemClass().
 */

And initializeSystemClass() uses native methods to initialize the standard streams to non-null values. Native code can reinitialize variables that are declared final.

Earthnut answered 1/8, 2013 at 8:55 Comment(3)
i think you trying to say about below code private static void initializeSystemClass() { setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true)); } private static native void setOut0(PrintStream out); but one thing i dont understand how can final variable initialized two times ?? one from above method and second time as my question code.Bucentaur
Well and good, but wont that fail once I have a computer that is so fast that it reaches this initialization method in less than 1 milliseconds? Or is currentTimeMillis() guaranteed to retrun a value > 0?Penetrant
Yes. currentTimeMillis() returns the current time? 0 means 1st Jan. 1970, and we're in 2013. A final variable can be initialized twice because it's native code, written in C, that initializes the variable. Such native code, part of the JVM itself, can of course bypass the JVM cecks applied to Java code.Earthnut
J
8

JVM calls the private static void initializeSystemClass() method which initializes it.

See these two lines of code :

setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true));
setErr0(new PrintStream(new BufferedOutputStream(fdErr, 128), true));

These are the two native methods :

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

There is a nice article on it.

Josephinajosephine answered 1/8, 2013 at 8:54 Comment(2)
The article doesn't explain the currentTimeMillis trick. Why is it used? To avoid some kind of optimisation?Tankoos
@kan: it’s funny (or sometimes rather frightening) to see such esoteric code even in fundamental Java classes. The nullInputStream() counterpart has a comment talking about prohibiting inlining, but null never gets inlined at compile-time and the way you get to the null will be irrelevant at runtime. Consequently, the Java 7 version doesn’t have that strange method anymore.Election
L
1

There is a getter and setter for out object.

Luehrmann answered 1/8, 2013 at 8:57 Comment(0)
A
0

When System class get initialized, it calls its initializeSystemClass() method, here is the code:

FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true));

In this code setOut0() is a native function implemented in System.c:

JNIEXPORT void JNICALL
Java_java_lang_System_setOut0(JNIEnv *env, jclass cla, jobject stream)
{
    jfieldID fid =
        (*env)->GetStaticFieldID(env,cla,"out","Ljava/io/PrintStream;");
    if (fid == 0)
        return;
    (*env)->SetStaticObjectField(env,cla,fid,stream);
}

This is a standard JNI code that sets System.out to the argument passed to it, this method calls the native method setOut0() which sets the out variable to the appropriate value.

System.out is final, it means it cannot be set to something else in initializeSystemClass() but using native code it is possible to modify a final variable.

Anabelanabella answered 27/8, 2017 at 3:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.