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
有一个getter
和setter
。
当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()
设置为其他东西,但是使用本机代码可以修改最终变量。