Объект PrintStream out инициализируется null, как мы вызываем метод на нем?
Я видел в классе System
, что объект out
(типа PrintStream
) инициализируется значением null
. Как мы можем вызвать метод, подобный System.out.prinln("");
?
В системном классе 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, и эта переменная является окончательной, поэтому она не может быть инициализирована далее, как мы можем использовать переменную" out".
4 ответа:
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()
используют собственные методы для инициализации стандартных потоков в ненулевые значения. Машинный код может повторно инициализировать переменные, объявленные конечными.
Когда системный класс инициализируется, он вызывает свой метод
initializeSystemClass()
, Вот код:FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out); setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true));
В этом коде setOut0 () является собственной функцией, реализованной в системе.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 в соответствующее значение.Система.out является окончательным, это означает, что он не может быть установлен на что-то другое в
initializeSystemClass()
, но с помощью собственного кода можно изменить a конечная переменная.