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

妖精的绣舞 提交于 2019-11-27 02:26:52

问题


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.


回答1:


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.




回答2:


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.




回答3:


There is a getter and setter for out object.




回答4:


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.



来源:https://stackoverflow.com/questions/17989275/printstream-object-out-is-initialized-by-null-how-we-call-method-on-it

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!