问题
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