2010-01-11 108 views
15

邏輯上,if(!foo)if(foo == false)是等效的。它們在Java中如何表示?編譯後兩者之間是否有區別,無論是字節碼還是性能?我無法在JLS中找到答案,並且搜索提出了大量= = == typos和==/equals()行爲的結果。 (在這種情況下,符號阻礙了我的搜索;對於未來的搜索者,否定運算符等於假,等於假,而不是條件)。Java中if(!foo)和if(foo == false)之間的性能差異(如果有的話)是什麼?

爲了避免CW爭論:這個問題不是問人們更喜歡哪種變體,哪種變體更好。我對語言實施的差異感興趣,所以有一個正確的答案。相關 - 但並非相當-一個重複數據刪除:Difference between while (x = false) and while (!x) in Java?

編輯:

普遍的共識似乎是一個很好的編譯器應該優化這些相同的事情。這是有道理的,也是我所懷疑的,但是 - 要求更多的學術問題 - 是否實際上在任何地方實施了行爲,還是僅僅是「合理的事情」?

+0

請記住這是編譯器特定的。 – danben 2010-01-11 17:09:12

+1

這裏有兩個問題。第一個問題是如何用Java表示的(字節碼)。第二個問是否在性能和字節碼方面存在差異(我認爲size是這裏的關注因素)。 – 2010-01-11 17:09:52

+3

任何不能識別這種優化的編譯器都不會使它在市場上走得太遠;) – 2010-01-11 17:10:26

回答

44

JLS將指定所需的語句行爲。但是,它們如何實現是編譯器和JVM的實現細節。

實際上,任何值得使用它的編譯器都應該爲這些語句發出相同的字節碼。即使不是,JVM也會對它們進行適當的優化。

此外,更好的方式來回答這個問題,是檢查自己,用javap

  1. 編譯一個Test.java具有以下內容:

    class Test { 
        void equals(boolean f) { 
         if (f == false) {} 
        } 
        void not(boolean f) { 
         if (!f) {} 
        } 
    } 
    $ javac Test.java 
    
  2. 去組裝起來:

    $ javap -c Test 
    Compiled from "Test.java" 
    class Test extends java.lang.Object{ 
    Test(); 
        Code: 
        0: aload_0 
        1: invokespecial #1; //Method java/lang/Object."<init>":()V 
        4: return 
    
    void equals(boolean); 
        Code: 
        0: iload_1 
        1: ifne 4 
        4: return 
    
    void not(boolean); 
        Code: 
        0: iload_1 
        1: ifne 4 
        4: return 
    
    } 
    

更新: 迴應你關於「學術」問題的問題。如上所述,JLS只關心行爲。標準中沒有任何內容確切地說明了應該如何實施(而且,JVMS提供了很多指導)。

只要編譯器保持相同的行爲,編譯器就可以自由地將其實現爲不同的,並具有不同的運行時性能。

+0

這就是我所說的善意!恭喜您的耐心等待! – 2010-01-11 17:20:29

+4

'javap -c'反彙編,它不反編譯。 – 2010-01-11 17:21:49

+1

很好的答案,謝謝。單獨提到javap對於+1來說已經足夠了,我以前從來沒有聽說過。 – Pops 2010-01-11 17:22:12

12

編譯器應該在內部解析爲相同的代碼,所以沒有區別。

+0

如何用notnoop的方式顯示它。 – 2010-01-11 17:18:15

+5

如果沒有任何參考,證明等(如果真實的話)沒有提供免費的陳述如何。 – 2010-01-11 17:23:08

0

嘗試decompiling the byte code並查看代碼的外觀有多不同。我猜想編譯可以幾乎相同地解決它們,任何細微的差異都會導致性能差異可以忽略不計。

+1

甚至看看字節碼本身http://stackoverflow.com/questions/800916/should-i-look-at-the-bytecode-that-is-produce-by-a-java-compiler – gingerbreadboy 2010-01-11 17:14:09

0

OK,一個更完整的答案:

如果有編譯器生成的這些變化,不同的字節碼我會感到非常驚訝。對於任何有興趣的人來說,使用反彙編程序檢查應該很容易。

鑑於這兩個表達式(最可能)編譯爲相同的字節碼,我預計大小或性能沒有差異。

0

的JLS說

在 表達的,如果塊被評估,則該表達式的 結果相比 真

在兩種不區分和比較對象情況下,表達式需要被評估,然後與真實情況進行比較。如果您正在檢查某個值而不是對其進行操作,那麼表達式評估就會變得無效,這可能會帶來理論上的性能優勢。

但是在這種情況下,我期望JIT爲這兩個表達式生成相同的字節碼。

0

對於這兩個結果生成的字節碼應該沒有什麼區別,如果它沒有爲非常有限資源的設備創建代碼(在這種情況下,您不應該用Java編寫)可以忽略不計,您應該決定編寫此代碼的兩種方式中的哪一種是更明顯的解決方案。

0

思考微觀優化在幾乎任何情況下浪費時間和導致錯誤的思維方式......

+0

請參閱我在問題主題中的評論。 – Pops 2010-01-11 20:48:10

相關問題