Java條件編譯是什麼?

喝水會長肉發表於2021-12-10

一、概述

條件編譯是指源程式的程式碼行,可以在滿足一定條件的情況下才進行編譯,而未選中的原始碼,不會生成中間碼或機器碼,即部分內容參與編譯。

條件編譯的好處: 對於不同硬體平臺或者軟體平臺,或者不同功能模組的程式碼,編寫到在同一個原始檔,從而方便程式的維護和移植。

很多程式設計語言都提供條件編譯的功能,比如C/++c採用前處理器指示符來達到條件編譯。而Java語言並沒有提供直接的前處理器,那麼Java是不是就沒有條件編譯呢?先告訴大家,答案是Java存在條件編譯,在這之前先說說C/C++的條件編譯。

二、C/C++條件編譯

對於C/C++,常見的預處理指令:

#define 巨集定義 #undef 取消已存在的巨集定義 #if 如果條件為真,則編譯後面的程式碼 #ifdef 如果巨集已定義,則編譯後面的程式碼 #ifndef 如果巨集未定義,則編譯後面的程式碼 #elif 如果前面的#if條件為假,並且當前條件為真,則編譯後面的程式碼 #endif 結束前面的#if……#else條件編譯語句塊 複製程式碼

條件編譯常見形式:

(1) 當通過#define已定義過該 識別符號,則程式編譯階段會選擇編譯程式碼段1,否則編譯程式碼段2

#ifdef  識別符號

       程式碼段 1
# else
       程式碼段 2
#endif

(2) 當通過#define未定義過該 識別符號,則程式編譯階段會選擇編譯程式碼段1,否則編譯程式碼段2。功能正好與(1)相反

#ifndef 識別符號

       程式碼段 1
# else
       程式碼段 2
#endif

(3) 當 表示式為真,則程式編譯階段會選擇編譯程式碼段1,否則編譯程式碼段2

#
if 表示式

       程式碼段 1
# else
       程式碼段 2
#endif


三、Java條件編譯

Java語法的條件編譯,是通過判斷條件為常量的 if語句實現的。其原理是Java語言的語法糖,根據if判斷條件的真假,編譯器直接把分支為false的程式碼塊消除。通過該方式實現的條件編譯,必須在方法體內實現,而無法在正整個Java類的結構或者類的屬性上進行條件編譯,這與C/C++的條件編譯相比,確實更有侷限性。在Java語言設計之初並沒有引入條件編譯的功能,雖有侷限,但是總比沒有更強。

反編譯分析技術:

對於Debug.java檔案,執行:

javac Debug
.java  
//編譯後 生成Debug.class檔案

javap -c Debug .class //通過javap,反編譯class檔案

接下來,展開幾項對比分析:

3.1 final對比

該對比項是針對是否採用final變數與非final變數的對比:

原始碼:


// 空方法

public void voidMethod ( ) {

}
//java學習交流:737251827  進入可領取學習資源及對十年開發經驗大佬提問,免費解答!
//final常量
private final boolean FINAL_FLAG_FALSE = false ;
public void constantFalseFlag ( ) {
    if ( FLAG_FALSE ) {
       System .out . println ( "debug log..." ) ;
    }
}

// 非final
private boolean  falseFlag = false ;
public void falseFlag ( ) {
    if ( falseFlag ) {
       System .out . println ( "debug log..." ) ;
    }
}


反編譯解析後的結果如下:


// 空方法

public void voidMethod ( ) ;
  Code :
      0 : return

//final常量
public void constantFalseFlag ( ) ;
  Code :
      0 : return

// 非final
public void falseFlag ( ) ;
  Code :
      0 : aload_0
      1 : getfield      # 3     // Field falseFlag:Z
      4 : ifeq           15
      7 : getstatic     # 5     // Field java/lang/System.out:Ljava/io/PrintStream;
    10 : ldc           # 6     // String debug log...
    12 : invokevirtual # 7     // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    15 : return

從反編譯的Code欄位,可以看出constantFalseFlag()方法體內的內容經過編譯後,對於常量false分支,是不可達分支,則在編譯成class位元組碼檔案時剪出該分支,最終效果等價於voidMethod()。而對於falseFlag()方法,則多了5條指令。

可見,對於常量為false的if語句,由於恆為false,等同於條件編譯的功能。

另外除了反編譯的方式來對比分析,如果不瞭解反編譯後的語法,還可以簡單地對比編譯後的.Class檔案的大小,也會發現if(false){}內部的程式碼塊會自動剪除。



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70010294/viewspace-2846996/,如需轉載,請註明出處,否則將追究法律責任。

相關文章