2011-11-14 17 views
3

大家都知道在編譯的時候javac的內聯常數,這可能會導致有趣的問題時,只有重新編譯應用程序的一部分,每個人都知道這裏通常的解決這個(讓這個javac的沒有按」不懂它實際上是一個編譯時間常數)System.out和最終目標內聯

但是,如果我們在Oracle JDK的System.class看代碼,我們看到以下內容:

public final static PrintStream out = null; 

所以大概out被反射或一些其他機制設置JVM初始化。但是這導致了一個問題:爲什麼不在這裏內聯? (至少我使用System.out.println()時從未得到空指針異常)。

是否javac的特殊情況下的場景,或者這實際上由語言規範合理地處理?

+0

只有文字的常量被內聯,其餘每個都被讀取 – bestsss

回答

1

static final結構的多種結果。文字可能是內聯 例如static final int xxx = 1,因爲這是明確的,但例如static final int xxx = returnOne()未必。

原始類型和字符串可以與文字只,其他所有的對象可以不被取代。最後但並非最不重要的System.out/in違反JLS()一旦最後一個字段被初始化,它總是包含相同的值,)。

很少有方法可以防止內聯:static final String xxx="xxx".intern();static final int yyy=123+return0();,因爲只能在運行時執行評估,所以javac將生成GETFIELD而不是BIPUSH(用於int)。

+0

有趣 - 在JLS中找不到定義,但將其限制爲文字和字符串可以解釋爲什麼它沒有這些黑客行爲。是的,我知道如何避免內聯字符串和整數 - 我只是在代碼中偶然發現它,並且驚訝於它沒有這些黑客行爲。 – Voo

+0

我讀到的第一本(也是唯一的)書(在java上)「java secrets」正在談論這個特性,也很明顯,因爲內聯任何內容的唯一方法是BIPUSH或常量表引用(我已經瞭解了一點後來在學習「java彙編程序」時) – bestsss

1

我的JDK代碼說out = nullInputStream()與該方法中的註釋:

/** 
* 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()電話setOut0(..)這是native,可能那張final左右。 System.setOut(..)以同樣的方式工作。

+0

是的它確實以相同的方式工作 – bestsss

+0

有趣 - 這是OpenJDK變體嗎?我正在使用oracle/sun實現。 – Voo

+0

@Voo,setIn和setOut從1.1開始就存在(也就是說,對於大多數人來說,永遠是永遠的),在所有的JDK版本中...遠遠早於java成爲GPL標準。 – bestsss