PrintStream对象out由null初始化,我们如何调用它上的方法



我在System类中看到,out对象(类型为PrintStream)是用null值初始化的。我们如何调用类似System.out.prinln("");的方法?In System类out变量初始化方式如下:

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();
     }
}

如上图所示,out变量由null初始化,这个变量是最终变量,所以它不能进一步初始化,那么我们如何使用"out"变量。

注释中有解释:

/**
 * 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().
 */

initializeSystemClass()使用本机方法将标准流初始化为非null值。本机代码可以重新初始化被声明为final的变量。

JVM调用初始化它的private static void initializeSystemClass()方法

请参阅以下两行代码:

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

这是两种本地方法:

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

有一篇很好的文章。

out对象有一个gettersetter

System类初始化时,会调用其initializeSystemClass()方法,代码如下:

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

在这段代码中,setOut0()是一个在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);
}

这是一个标准的JNI代码,它将System.out设置为传递给它的参数,该方法调用本地方法setOut0(),该方法将out变量设置为适当的值。

System.out是final,这意味着它不能在initializeSystemClass()中设置为其他值,但使用本机代码可以修改final变量。

相关内容

  • 没有找到相关文章

最新更新