Когда класс 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
является окончательным, это означает, что он не может быть установлен на что-то другое в initializeSystemClass (), но с помощью собственного кода можно изменить конечную переменную.