程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java中的條件編譯

Java中的條件編譯

編輯:關於JAVA
 

在代碼中添加大量log,對於CPU和內存的影響如何,會不會降低性能?相信有不少人對此有疑問,本文將詳細解答該問題。

一、概述#

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

條件編譯的好處:對於不同硬件平台或者軟件平台,或者不同功能模塊的代碼,編寫到在同一個源文件,從而方便程序的維護和移植。

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

二、C/C++條件編譯#

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

#include 引入源代碼文件
#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(){

}

//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){}內部的代碼塊會自動剪除。

 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved