假設我在C代碼中有這樣的東西。我知道你可以使用#define
來代替編譯器,但是出於好奇心,我問編譯器是否也會把這件事情弄清楚。編譯器會優化這個
我認爲這對Java編譯器來說更重要,因爲它不支持#define
。
const int CONDITION = 0;
........
// Will the compiler compile this?
if (CONDITION)
{
}
.......
假設我在C代碼中有這樣的東西。我知道你可以使用#define
來代替編譯器,但是出於好奇心,我問編譯器是否也會把這件事情弄清楚。編譯器會優化這個
我認爲這對Java編譯器來說更重要,因爲它不支持#define
。
const int CONDITION = 0;
........
// Will the compiler compile this?
if (CONDITION)
{
}
.......
在Java中,代碼if甚至不是編譯代碼的一部分,它必須編譯,但不會寫入已編譯的字節碼,它實際上取決於編譯器,但我不知道編譯器不會優化。它的規則在the JLS定義:
優化編譯器可能會意識到語句x = 3;將永遠不會 被執行和毫安y選擇從 生成的類文件中省略該語句的代碼,但是語句x = 3;在這裏指定的技術意義上不被視爲 「無法達到」。
這種區別對待的理由是讓程序員 定義「標誌變量」,如:
static final boolean DEBUG = false;
,然後編寫代碼,如:
if (DEBUG) { x=3; }
的想法是,它應該可以將DEBUG 的值從false更改爲true或從true更改爲false,然後正確編譯代碼 ,而不對程序文本進行其他更改。
不知道C.
Java SE 9的更新鏈接:https://docs.oracle.com/javase/specs/jls/se9/html/jls-14.html#d5e23594 –
首先,Java不允許非布爾在條件語句像C(if
,while
等)。另外,如果你在你的if
抽查中有一個「常數」表達」,編譯器將內部警告你,你是比較相同的表現,所以我敢肯定,它優化掉了。如
final int i = 1;
if (1 == i) { // warning
System.out.println("HI");
}
如果'i'不是'1',這段代碼只會產生警告(「死代碼」,Java 6)! –
我記得在我的Java和C#程序,它確實情景(優化出來)。但是我也知道這很大程度上取決於編譯器設置 - 因此情況太不確定。
在Java場景中,我們在一個Java源文件中使用了const值,而在另一個類(文件)中使用了它們。發生了什麼事,當我們用const值更改並重新編譯文件時,使用部分的流程中沒有任何變化。我們必須重新編譯整個項目(這是它被優化的證明)。
不要問這樣簡單的問題(其中唯一正確的答案是「用你的編譯器試一試」) - 爲什麼不試試呢?
public class Test {
public static void main(String[] args) {
if (true) {
System.out.println("Yep");
}
boolean var = false;
if (var) {
System.out.println("Nope");
}
final boolean var2 = false;
if (var2) {
System.out.println("Nope");
}
}
}
javac .\Test.java
javap -c Test
Compiled from "Test.java"
public class Test {
public Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String Yep
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: iconst_0
9: istore_1
10: iload_1
11: ifeq 22
14: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
17: ldc #3 // String Yep
19: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
22: return
}
你不需要知道很多關於Java/C#字節碼或組件能夠理解這是怎麼回事。現在去C#試試。
下面是具體到C語言。我不知道Java如何處理它。
由於int
被定義爲const
,if (i)
在這裏變成了no-op
指令。一個聰明的編譯器應該能夠優化掉那個空的if
語句。
例:VC 2008
非空{}
與if
聲明:
const int i = 1;
// mov dword ptr [i], 1
if (i)
// mov eax, 1
// test eax, eax
// je wmain+35h
{
int j = 2;
// move dword ptr [j], 2
}
// ..
空{}
與if
聲明:
const int i = 1;
// mov dword ptr [i], 1
if (i)
{
}
// ..
我只是做了一個快速檢查與以下一段代碼爲
public class Test {
private static final boolean flag = true;
public static void main(String[] args) throws InterruptedException {
if(flag){
System.out.println("1");
System.out.println("1");
System.out.println("1");
System.out.println("1");
System.out.println("1");
System.out.println("1");
System.out.println("1");
System.out.println("1");
System.out.println("1");
}
}
}
當標誌=真,將得到的類文件的大小是708
當標誌=假。結果類文件的大小是462
這意味着編譯當然有,優化靜態最終值
Java編譯器必須檢測顯然無法訪問的代碼,這是一個語言要求。味精是最後但編譯器既不抱怨味精沒有初始化,也不抱怨,它就會被初始化兩次
static final boolean flag = true;
public static void main(String[] args) {
final String msg;
if (flag)
msg = "true";
if (!flag)
msg = "false";
System.out.println(msg);
}
注:所以下面的代碼將編譯沒有錯誤。大多數編譯器不會將死代碼寫入類文件。但即使如此,JIT也會優化它。
C++也有一個編譯時間常量的概念。 const int是一個編譯時間常量,所以它可以用作非類型模板參數。因此,即使編譯時沒有指定優化選項,每個理智的C++編譯器都會檢測並優化該類型的明顯死代碼。
你爲什麼不嘗試一下,看看產生的二進制文件? –
特別是,您可以在您的Class上使用javap -c命令來打印出字節碼,這實際上很容易閱讀。 http://download.oracle.com/javase/1,5.0/docs/tooldocs/windows/javap.html – Brigham
我記得把'if(false){...}'作爲推薦的排除Java代碼的方法,在C預處理器中使用'la'#if'。那是幾年前。 – Joe