Объект 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 6

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() используют собственные методы для инициализации стандартных потоков в ненулевые значения. Машинный код может повторно инициализировать переменные, объявленные конечными.

Существует getter и setter для out объекта.

Когда системный класс инициализируется, он вызывает свой метод 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 конечная переменная.