2013-03-22 67 views
6

以下是從java.lang.System中類代碼(JDK 1.6版)怪 '出來' 變量,的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(); 
} 

當我們寫在我們的代碼System.out.println("Something");那麼爲什麼不難道我們得到NullPointerException異常甚至「出」,當設置爲「空」

總之out將通過在系統級

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

以下setOut方法來設置他們n爲什麼JLS需要nullPrintStream方法?

+0

'if(currentTimeMillis()> 0){return null; }'=>這真的很奇怪..在JDK 7中,它很簡單:'public final static PrintStream out = null;'。 – assylias 2013-03-22 08:51:20

+1

@assylias安撫早期版本的javac/JIT編譯器。如果沒有'if',編譯器就會意識到它總是返回'null'並將'out'編譯爲編譯時常量,並帶來所有不好的後果。 – 2013-03-22 08:56:56

+0

這意味着一旦足夠的時間來使'currentTimeMillis()'的值溢出'long'的最大值,所有運行早於Java 7的虛擬機的應用程序都會失敗並出現錯誤:'java.lang 。ExceptionInInitializerError引發java.lang.System.nullPrintStream(未知源)的java.lang.NullPointerException'或類似錯誤。 – gparyani 2013-08-14 22:21:52

回答

8

看看在private static void initializeSystemClass() - 這種方法被調用來啓動的事情了,它調用setOut0()這是一個native方法。這將Stream連接到應該的位置。

所以即使可能看起來public static final它實際上不是,native代碼更改它。

編輯

OP問那麼,爲什麼需要JLS方法nullPrintStream?

這與java編譯器做的事情 - 將「內聯」 static final領域,如果他們被分配到的東西常在編譯的時候,像null。編譯器實際上會用常量替換每個引用的字段。

這會破壞初始化,因爲對象不再持有對Stream的引用,而是對null。將流分配給方法的返回可防止內聯。

有人可能稱之爲骯髒的黑客攻擊。誤導俾斯麥「JDK就像香腸,最好不要看到它被製造出來」。

+0

雖然如上所述,在Java 7中它已被糾正 - 所以它必須如Marko所示,使用較老的編譯器。 – assylias 2013-03-22 09:14:33

+0

他們可以定義'public final static PrintStream out = null;'。幫助理解「在線」靜態最終字段。 – AmitG 2013-03-22 09:38:55

+2

@AmitG看看[this](http://stackoverflow.com/questions/5173372/java-static-final-values-replaced-in-code-when-compiling)和[this](http:// docs.oracle.com/javase/specs/jls/se7/html/jls-13.html#jls-13.4.9)。如果將某些東西定義爲編譯時間常量,那麼(Java 6)編譯器將使用該信息來優化代碼 - 它將用文字替換任何引用。因此,編譯器會將'System.out'替換爲'null',因爲它假定'System.out'不會因爲它被設置爲'null'而改變,並且它是'final'。 – 2013-03-22 09:56:47

2

這就是System.out類的初始化過程。

還有一種方法:

private static native void setOut0(PrintStream out); 

被稱爲在下面的方法:

private static void initializeSystemClass() { 
2

System.in,out和err由JVM從本機代碼管理。這個帶有nullPrintStream()的整個魔術就是爲了防止javac內聯這些字段。由於Java 7看起來像

public final static PrintStream out = null;