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

我在System类中看到out对象(类型为PrintStream )初始化为null值。 我们如何调用System.out.prinln(""); ? 在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初始化,这个变量是final,所以它不能进一步初始化,那么我们如何使用“out”变量。

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

有一篇很好的文章 。

解释在评论中:

 /** * 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()使用本机方法将标准流初始化为非空值。 本机代码可以重新初始化声明为final的变量。

对象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()设置为其他东西,但是使用本机代码可以修改最终变量。