2013-08-01 2 views
5

Я видел в классе System, что объект out (типа PrintStream) инициализирован значением null. Как мы можем назвать метод вроде System.out.prinln("");? В системной переменной класса инициализируется, как таким образом:Объект PrintStream 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 переменной инициализируется нулевым и эта переменная является окончательным, поэтому он не может инициализировать дальше, то как мы можем использовать «из» переменной.

+0

может помочь вам http://stackoverflow.com/questions/9454866/out-in-system-out-println – Prabhaker

ответ

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); 

Существует nice article on it.

+1

Статья не объясняет трюк 'currentTimeMillis'. Почему он используется? Чтобы избежать какой-то оптимизации? – kan

+0

@kan: смешно (или иногда довольно страшно) видеть такой эзотерический код даже в основных классах Java. [Параметр 'nullInputStream()' (http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/System.java#1063) имеет комментарий, говорящий о запрете inlining, но 'null' никогда не становится встроенным во время компиляции, и способ, которым вы попадаете в' null', будет неактуальным во время выполнения. Следовательно, [версия Java 7] (http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/java/lang/System.java/#104) У меня этот странный метод. – Holger

6

Объяснение в комментариях:

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

+0

Я думаю, что вы пытаетесь сказать примерно ниже код private static void initializeSystemClass() { \t setOut0 (новый PrintStream (новый BufferedOutputStream (fdOut, 128), true)); } частный статический нативный пустой наборOut0 (PrintStream out); но одна вещь, я не понимаю, как окончательная переменная инициализируется два раза ?? один из методов выше и второй раз в качестве моего кода вопроса. – Hits

+0

Ну и хорошо, но это не так, если у меня есть компьютер, который настолько быстр, что достигает этого метода инициализации менее чем за 1 миллисекунду? Или currentTimeMillis() гарантированно возвращает значение> 0? – Ingo

+1

Да. currentTimeMillis() возвращает текущее время? 0 означает 1 января 1970 года, и мы в 2013 году. Окончательная переменная может быть инициализирована дважды, потому что это собственный код, написанный на C, который инициализирует переменную. Такой собственный код, являющийся частью самого JVM, может, конечно, обойти JVM-циклы, применяемые к Java-коду. –

1

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

0

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