----?基礎知識
-- 編譯時
編譯器將源代碼翻譯成機器能夠讀懂的代碼,如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{} 語句塊來處理檢測異常。編譯器會分析哪些異常會在執行一個方法或者構造函數的時候拋出。