2012-01-29 69 views
3

我在我的應用程序下面的代碼:Java編譯器不優化靜態最終字符串。爲什麼?

public static final boolean DEBUG = true; 
    public static final boolean REL = !DEBUG; 

    private static final String DEBUG_OR_RELEASE = (REL) ? "RELEASE_VER" : "DEBUG_VER"; 

我認爲Java編譯器將完全從生成的.apk文件消除"DEBUG_VER"字符串(當通過Proguard的出口),但是當我檢查.apk文件,我在那裏看到了「DEBUG_VER」字符串。

爲什麼?我錯過了什麼?我做錯了什麼?

+0

那麼,如果你不認爲你應該看到「RELEASE_VER」,那麼可能你正在編譯調試,通常這種優化在調試模式下被禁用。 – 2012-01-29 02:20:11

+0

除此之外,即使語句經過優化,字符串文字可能會留在常量池中。它基本上是無害的。 – 2012-01-29 02:21:14

+0

'DEBUG_OR_RELEASE =(REL)? 「DEBUG_VER」:「DEBUG_VER」'?真?請發佈您的真實代碼。 – erickson 2012-01-29 03:53:36

回答

1

根據您發佈的內容,DEBUG爲真,因此REL爲false,因此(REL) ? "RELEASE_VER" : "DEBUG_VER"應產生「DEBUG_VER」。

這正是你所觀察什麼,所以如果你希望看到「RELEASE_VER」相反,你應該設置:

public static final boolean DEBUG = false; 

試一下,看看會發生什麼。

+0

謝謝,這很有效。這意味着我現在必須記住,只要我導出發行版本就將'boolean DEBUG'更改爲* false *。哎喲。 – ateiob 2012-01-29 06:12:08

1

即使變量設置爲true,它仍在運行。 ?:語句是可執行代碼和操作代碼的一部分,由於Java沒有預編譯器,因此每次編譯時都會運行

Java不會自動推斷和簡化操作,即使邏輯上操作在每次迭代中都是相同的。

+0

感謝但根據[這](http://stackoverflow.com/a/1813873)它應該是可能的。那個答案是不正確的? – ateiob 2012-01-29 02:45:50

+0

我認爲他的意思是你會產生相同的結果,而不是從編譯中刪除它。但是如果我錯了,那麼是的,那個答案是不正確的。 – Zyerah 2012-01-29 02:49:07

+0

即使沒有預處理器,Java編譯器也會(並且在某些情況下必須)移除明顯無法訪問的代碼,例如基於最終布爾值爲false的條件。它在Java語言規範第14.21節中進行了討論,並且在實踐中很容易驗證。 – 2012-01-29 10:13:43

3

編譯爲java字節碼沒有進行優化(除了極少數例外)。

許多書籍爲簡化起見,「編譯」階段是優化發生時,但它是錯誤的。當優化真正發生時,字節碼文件是由JVM處理的。所以爲了通關:優化可能發生在編譯字節碼到機器本地代碼時,這是由JVM工具完成的。

有時根本沒有優化(JVM在解釋模式下工作)。有時由JIT(Just In Time編譯器)進行一些優化。有時候,自適應優化器負責優化(不僅優化,而且在執行附加操作的情況下分析代碼執行)。

最後,你的文件沒有問題。這就是Java世界的工作原理。

「但爲什麼?」 - 你可能會問。在字節碼中保留這種「無用的」信息的原因是因爲你永遠無法確定可以消除多少代碼,所以不同JVM提供的優化仍然可以高效工作。最好的辦法就是不要抹去任何信息,讓優化者去完成他們的工作。

+0

'優化真正發生時,字節碼文件加載到JVM'時 - 這有點誤導,並且與您稍後說的不一致。 JIT在加載時不會優化方法,但只有在解釋模式下執行了特定次數後纔會對其進行優化。 (可怕的簡化) – Voo 2012-01-29 02:35:32

+0

做了一個小的編輯,使它更加正確,但我仍然意識到,在這裏做任何簡化可能是誤導。 – msi 2012-01-29 02:44:31

+0

@msi謝謝。這是有道理的,但在我的情況下,我*想*從發佈APK中刪除「DEBUG_VER」字符串。我怎麼能做到這一點? – ateiob 2012-01-29 02:48:18