java中的編譯時與運行時


----?基礎知識

    -- 編譯時

    編譯器將源代碼翻譯成機器能夠讀懂的代碼,如java中就是翻譯成jvm能夠讀懂的字節碼文件。簡單說,編譯時就是機器幫我們檢查代碼是否有出現語法錯誤,關鍵字寫錯之類的,是為之后的類加載做好准備,所以,在這個過程中並不會出現什么分配內存之類的操作。

   -- 運行時

    這個過程是指將編譯好后的儲存在磁盤上的字節碼文件(.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 = number1 * number2; //line A
 
 int product2 = number3 * number4; //line B
 
 }
 
}

--- 分析

    同時被static和final修飾的常量稱作編譯時常量,所以number1 和 number2在編譯時已經被加載了,即product1 在編譯期間就已經確定好了值為多少。而number3 和number4 只有在運行時,分配好了內存空間並且才能被成功賦值,所以product2 的值只有在運行時才能夠確定是多少。反編譯如下:

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;
 }
}

 

---- 舉個栗子

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

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

   如果編譯器調用的方法是下面

new Test().A("classlodaer");

   那么它就會在編譯的時候自己去尋找menthod #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;
 } 
}

   如果編譯器遇到如下代碼,就在編譯時就無法判斷究竟傳入的參數是A類型還是B類型,只有在運行時才能夠進行確定,進而來判斷要調用方法#3還是#4

public int evaluate(A reference, int arg2) {
 int result = reference.compute(arg2);
}

 

---- 舉個栗子

  泛型(又稱類型檢驗):這個是發生在編譯期的。編譯器負責檢查程序中類型的正確性,然后把使用了泛型的代碼翻譯或者重寫成可以執行在當前JVM上的非泛型代碼。這個技術被稱為“類型擦除“。

    public class Test4 {
        public static void main(String[] args) {
            ArrayList<String> arrayList1=new ArrayList<String>();
            arrayList1.add("abc");
            ArrayList<Integer> arrayList2=new ArrayList<Integer>();
            arrayList2.add(123);
            System.out.println(arrayList1.getClass()==arrayList2.getClass());
        }
    }

---- 分析

   在這個例子中,我們定義了兩個ArrayList數組,不過一個是ArrayList<String>泛型類型,只能存儲字符串。一個是ArrayList<Integer>泛型類型,只能存儲整形。最后,我們通過arrayList1對象和arrayList2對象的getClass方法獲取它們的類的信息,最后發現結果為true。說明泛型類型String和Integer都被擦除掉了,只剩下了原始類型

 

---- 舉個栗子

  異常:分為編譯時異常和運行時異常

  運行時異常(RuntimeException)也稱作未檢測的異常(unchecked exception),這表示這種異常不需要編譯器來檢測。RuntimeException是所有可以在運行時拋出的異常的父類。一個方法除要捕獲異常外,如果它執行的時候可能會拋出。RuntimeException的子類,那么它就不需要用throw語句來聲明拋出的異常。

   例如:NullPointerException,ArrayIndexOutOfBoundsException,等等

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

 


免責聲明!

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



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