首頁  >  文章  >  Java  >  實例詳解java執行編譯與執行兩種概念

實例詳解java執行編譯與執行兩種概念

Y2J
Y2J原創
2017-05-05 15:05:231262瀏覽

本篇文章透過實例對java程式編譯時與運行時進行了詳解,需要的朋友可以參考下

Java編譯時與運行時很重要的概念,但是一直沒有明晰,這次專門部落格寫明白概念.

基礎概念


#編譯時顧名思義就是正在編譯的時候.那啥叫編譯呢?就是編譯器幫你把源代碼翻譯成機器能識別的代碼.(當然只是一般意義上這麼說,實際上可能只是翻譯成某個中間狀態#的語言.例如Java只有JVM識別的字節碼,.另外還有啥連結器.彙編器.為了了便於理解我們可以統稱為編譯器)

那編譯時就是簡單的作一些翻譯工作,比如檢查老兄你有沒有粗心寫錯啥關鍵字了啊.有啥詞法分析,語法分析之類的過程.就像個老師檢查學生的作文中有沒有錯字和病句一樣.如果發現啥錯誤編譯器就告訴你.所以有時有些人說編譯時還分配內存啥的肯定是錯誤的說法.

運行時

所謂運行時就是程式碼跑起來了.被裝載到內存中去了.(你的程式碼保存在磁碟上沒裝入內存之前是個死傢伙.只有跑到內存中才變成活的).而運行時類型檢查就與前面講的編譯時類型檢查(或靜態類型檢查)不一樣.不是簡單的掃描程式碼.而是在記憶體中做些操作,做些判斷.(這樣很多編譯時無法發現的錯誤,在運行就可以發現報錯了,最好還是寫的的時候就避免這個邏輯錯誤就好了)

#舉列子

int arr[] = {1,2,3}; 
int result = arr[4]; 
System.out.println(result); 
Exception in thread “main” java.lang.ArrayIndexOutOfBoundsException: 4

上面的程式碼你一瞧你知道是錯誤的程式碼,陣列越界了.但用編譯器沒有報錯,run後才出現了ArrayIndexOutOfBoundsException.可見編譯器其實還是挺笨的,還沒你腦瓜子那麼聰明啊,於是你想雖然編譯器笨了點,但運行起來時發現了錯誤也還不算太壞.

#面試題

理解这几个概念可以更好地帮助你去了解一些基本的原理。下面是初学者晋级中级水平需要知道的一些问题。 
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指令都是檢視編譯後的程式碼(例如,字節碼)的利器。

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

public class {
 public static void evaluate(String param1); // method #1
 public static void evaluate(int param1); // method #2
}

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

1evaluate(“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

泛型(又稱型別檢定):這個是發生在編譯期的。編譯器負責檢查程式中類型的正確性,然後把使用了泛型的程式碼翻譯或重寫成可以執行在目前JVM上的非泛型程式碼。這個技術被稱為「類型擦除」。

換句話說,編譯器會擦除所有在尖括號裡的類型信息,來保證和版本1.4.0或更早版本的JRE的兼容性。

1List myList = new ArrayList(10);

編譯後變成了:

1List myList = new ArrayList( 10);

異常(Exception):你可以使用執行時間異常或編譯時異常。

執行時期異常(RuntimeException)也稱為未偵測的異常(unchecked exception),這表示這種異常不需要編譯器來偵測。

RuntimeException是所有可以在執行時間拋出的例外的父類別。一個方法除要捕獲異常外,如果它執行的時候可能會拋出

RuntimeException的子類,那麼它就不需要用throw語句來宣告拋出的例外。

例如:NullPointerException,ArrayIndexOutOfBoundsException,等等

受檢查異常(checked exception)都是編譯器在編譯時進行校驗的,透過throws語句或try {}cathch{} 語句區塊來處理偵測異常。編譯器會分析哪些異常會在執行一個方法或建構函數的時候拋出。

【相關推薦】

1. Java免費影片教學

#2. 阿里巴巴Java開發手冊

#3. JAVA初級入門影片教學

以上是實例詳解java執行編譯與執行兩種概念的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn