2013-03-22 8 views
6

Im Folgenden finden Sie den Code aus java.lang.System Klasse (JDK Version 1,6)seltsam 'out' Variable, System.out.println()

public final static PrintStream out = nullPrintStream(); //out is set to 'null' 

private static PrintStream nullPrintStream() throws NullPointerException { 
    if (currentTimeMillis() > 0) { 
     return null; 
    } 
    throw new NullPointerException(); 
} 

wenn wir System.out.println("Something"); in unserem Code schreiben, warum dann don‘ t erhalten wir Nullpointer auch wenn 'out' ist auf 'null'

Wie auch immer out wird über folgende setOut Methode in System-Klasse

public static void setOut(PrintStream out) { 
    checkIO(); 
    setOut0(out); 
} 

eingestellt werden Sie Warum benötigt JLS nullPrintStream Methode?

+0

'if (currentTimeMillis()> 0) {return null; } '=> das ist wirklich seltsam .. In JDK 7 ist es einfach:' public final static PrintStream out = null; '. – assylias

+1

@assylias Es ist alles da, um die früheren Versionen von Javac/JIT-Compilern zu beschwichtigen. Ohne diesen 'if' könnte der Compiler realisieren, dass er immer' null' zurückgibt und 'out' als eine Kompilierzeitkonstante mit all den schlimmen Folgen kompiliert. –

+0

Das bedeutet, dass sobald genug Zeit verstrichen ist, um den Wert von 'currentTimeMillis()' den Maximalwert für ein 'long' überlaufen zu lassen, alle Anwendungen mit virtuellen Maschinen älter als Java 7 mit einem Fehler fehlschlagen: 'java.lang .ExceptionInInitializerError Wird von java.lang.NullPointerException bei java.lang.System.nullPrintStream (Unknown Source) oder ähnlich verursacht. – gparyani

Antwort

8

Werfen Sie einen Blick auf die private static void initializeSystemClass() - diese Methode wird aufgerufen, Dinge zu starten, ruft setOut0() ist eine native Methode. Dies bindet die Stream in, wo es sein soll.

Also auch wenn das Feld aussehenpublic static final es ist eigentlich nicht, die native Code ändert.

EDIT

OP fragt Warum JLS nullPrintStream Methode braucht?

Dies ist mit den Java-Compiler zu tun - es wird „inline“ static final Felder, wenn sie konstant bei der Kompilierung zu etwas zugeordnet sind, wie null. Der Compiler wird tatsächlich jeden Verweis auf das Feld durch die Konstante ersetzen.

Dies würde die Initialisierung unterbrechen, da Objekte keinen Bezug mehr auf Stream, sondern auf null haben würden. Das Zuweisen des Streams zur Rückgabe einer Methode verhindert das Inlining.

Manche könnten es einen schmutzigen Hack nennen. Um Bismarck falsch zu zitieren "Das JDK ist wie Würstchen, es ist am besten, es nicht gemacht zu sehen".

+0

Obwohl wie oben erwähnt, in Java 7 wurde es behoben - so muss es mit älteren Compilern wie von Marko angegeben. – assylias

+0

Sie hätten 'public final static PrintStream out = null;' definieren können. Helfen Sie, das statische Endfeld "lnline" zu verstehen. – AmitG

+2

@AmitG werfen Sie einen Blick auf [diese] (http://stackoverflow.com/questions/5173372/java-static-final-values-replaced-in-code-when-compiling) und [dies] (http: // docs.oracle.com/javase/specs/jls/se7/html/jls-13.html#jls-13.4.9). Wenn Sie etwas als Kompilierzeitkonstante definieren, würde der (Java 6) -Compiler diese Informationen verwenden, um den Code zu optimieren - er würde alle Referenzen durch das Literal ersetzen. Alles, was "System.out" heißt, würde vom Compiler durch "null" ersetzt, da es annimmt, dass 'System.out' nicht geändert werden kann, da es auf 'null' gesetzt ist und es 'final' ist. –

2

So wird die System.out-Klasse initialisiert.

Es gibt auch eine Methode:

private static native void setOut0(PrintStream out); 

die in der folgenden Methode aufgerufen wird:

private static void initializeSystemClass() { 
2

System.in, out und err werden von der JVM aus nativem Code verwaltet. Diese ganze Magie mit nullPrintStream() war da, um zu verhindern, dass javac diese Felder einreiht. Seit java 7 sieht es so aus:

public final static PrintStream out = null; 
Verwandte Themen