編譯時、運行時、構建時(一)


在開發和設計的時候,我們需要考慮編譯時,運行時以及構建時這三個概念。理解這幾個概念可以更好地幫助你去了解一些基本的原理。下面是初學者晉級中級水平需要知道的一些問題。

 

Q.下面的代碼片段中,行A和行B所標識的代碼有什么區別呢?

public class ConstantFolding {

static final int number1 = 5;

static final int number2 = 6;

static int number3 = 5;

static int number4= 6;

public static void main(String[ ] args) {

int product1 = number1 * number2; //line A

int product2 = number3 * number4; //line B

}

}

 

A.在行A的代碼中,product的值是在編譯期計算的,行B則是在運行時計算的。如果你使用Java反編譯器(例如,jd-gui)來反編譯ConstantFolding.class文件的話,那么你就會從下面的結果里得到答案。

 

 

public class ConstantFolding {

static final int number1 = 5;

static final int number2 = 6;

static int number3 = 5;

static int number4 = 6;

public static void main(String[ ] args) {

int product1 = 30;

int product2 = number3 * number4;

}

}

常量折疊是一種Java編譯器使用的優化技術。由於final變量的值不會改變,因此就可以對它們優化。Java反編譯器和javap命令都是查看編譯后的代碼(例如,字節碼)的利器。

 

 

 

Q.你能想出除了代碼優化外,在什么情況下,查看編譯過的代碼是很有幫助的?

 

A.Java里的泛型是在編譯時構造的,可以通過查看編譯后的class文件來理解泛型,也可以通過查看它來解決泛型相關的問題。

 

 

 

Q.下面哪些是發生在編譯時,運行時,或者兩者都有?

 

A. 方法重載:這個是發生在編譯時的。方法重載也被稱為編譯時多態,因為編譯器可以根據參數的類型來選擇使用哪個方法。

 

public class {

public static void evaluate(String param1); // method #1

public static void evaluate(int param1); // method #2

}

如果編譯器要編譯下面的語句的話:

 

evaluate(“My Test Argument passed to param1”);

 

它會根據傳入的參數是字符串常量,生成調用#1方法的字節碼

 

 

 

方法覆蓋:這個是在運行時發生的。方法重載被稱為運行時多態,因為在編譯期編譯器不知道並且沒法知道該去調用哪個方法。JVM會在代碼運行的時候做出決定。

 

public class A {

public int compute(int input) { //method #3

return 3 * input;

}

}

 

public class B extends A {

@Override

public int compute(int input) { //method #4

return 4 * input;

}

}

子類B中的compute(..)方法重寫了父類的compute(..)方法。如果編譯器遇到下面的代碼:

 

public int evaluate(A reference, int arg2) {

int result = reference.compute(arg2);

}

編譯器是沒法知道傳入的參數reference的類型是A還是B。因此,只能夠在運行時,根據賦給輸入變量“reference”的對象的類型(例如,A或者B的實例)來決定調用方法#3還是方法#4.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM