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.