java編譯時(shí)與運(yùn)行時(shí)概念與實(shí)例詳解
Java編譯時(shí)與運(yùn)行時(shí)很重要的概念,但是一直沒(méi)有明晰,這次專門博客寫明白概念.
基礎(chǔ)概念
編譯時(shí)
編譯時(shí)顧名思義就是正在編譯的時(shí)候.那啥叫編譯呢?就是編譯器幫你把源代碼翻譯成機(jī)器能識(shí)別的代碼.(當(dāng)然只是一般意義上這么說(shuō),實(shí)際上可能只是翻譯成某個(gè)中間狀態(tài)的語(yǔ)言.比如Java只有JVM識(shí)別的字節(jié)碼,.另外還有啥鏈接器.匯編器.為了了便于理解我們可以統(tǒng)稱為編譯器)
那編譯時(shí)就是簡(jiǎn)單的作一些翻譯工作,比如檢查老兄你有沒(méi)有粗心寫錯(cuò)啥關(guān)鍵字了啊.有啥詞法分析,語(yǔ)法分析之類的過(guò)程.就像個(gè)老師檢查學(xué)生的作文中有沒(méi)有錯(cuò)別字和病句一樣.如果發(fā)現(xiàn)啥錯(cuò)誤編譯器就告訴你.所以有時(shí)一些人說(shuō)編譯時(shí)還分配內(nèi)存啥的肯定是錯(cuò)誤的說(shuō)法.
運(yùn)行時(shí)
所謂運(yùn)行時(shí)就是代碼跑起來(lái)了.被裝載到內(nèi)存中去了.(你的代碼保存在磁盤上沒(méi)裝入內(nèi)存之前是個(gè)死家伙.只有跑到內(nèi)存中才變成活的).而運(yùn)行時(shí)類型檢查就與前面講的編譯時(shí)類型檢查(或者靜態(tài)類型檢查)不一樣.不是簡(jiǎn)單的掃描代碼.而是在內(nèi)存中做些操作,做些判斷.(這樣很多編譯時(shí)無(wú)法發(fā)現(xiàn)的錯(cuò)誤,在運(yùn)行就可以發(fā)現(xiàn)報(bào)錯(cuò)了,最好還是寫的的時(shí)候就避免這個(gè)邏輯錯(cuò)誤就好了)
舉列子
int arr[] = {1,2,3}; int result = arr[4]; System.out.println(result); Exception in thread “main” java.lang.ArrayIndexOutOfBoundsException: 4
上面的代碼你一瞧你知道是錯(cuò)誤的代碼,數(shù)組越界了.但用編譯器沒(méi)有報(bào)錯(cuò),run后才出現(xiàn)了ArrayIndexOutOfBoundsException.可見編譯器其實(shí)還是挺笨的,還沒(méi)你腦瓜子那么聰明啊,于是你想雖然編譯器笨了點(diǎn),但運(yùn)行起來(lái)時(shí)發(fā)現(xiàn)了錯(cuò)誤也還不算太壞.
面試題
理解這幾個(gè)概念可以更好地幫助你去了解一些基本的原理。下面是初學(xué)者晉級(jí)中級(jí)水平需要知道的一些問(wèn)題。 Q.下面的代碼片段中,行A和行B所標(biāo)識(shí)的代碼有什么區(qū)別呢? 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的值是在編譯期計(jì)算的,行B則是在運(yùn)行時(shí)計(jì)算的。如果你使用Java反編譯器(例如,jd-gui)來(lái)反編譯ConstantFolding.class文件的話,那么你就會(huì)從下面的結(jié)果里得到答案。
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編譯器使用的優(yōu)化技術(shù)。由于final變量的值不會(huì)改變,因此就可以對(duì)它們優(yōu)化。Java反編譯器和javap命令都是查看編譯后的代碼(例如,字節(jié)碼)的利器。
方法重載:這個(gè)是發(fā)生在編譯時(shí)的。方法重載也被稱為編譯時(shí)多態(tài),因?yàn)榫幾g器可以根據(jù)參數(shù)的類型來(lái)選擇使用哪個(gè)方法。
public class { public static void evaluate(String param1); // method #1 public static void evaluate(int param1); // method #2 }
如果編譯器要編譯下面的語(yǔ)句的話:
1evaluate(“My Test Argument passed to param1”);
它會(huì)根據(jù)傳入的參數(shù)是字符串常量,生成調(diào)用#1方法的字節(jié)碼
方法覆蓋:這個(gè)是在運(yùn)行時(shí)發(fā)生的。方法重載被稱為運(yùn)行時(shí)多態(tài),因?yàn)樵诰幾g期編譯器不知道并且沒(méi)法知道該去調(diào)用哪個(gè)方法。JVM會(huì)在代碼運(yùn)行的時(shí)候做出決定。
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); }
編譯器是沒(méi)法知道傳入的參數(shù)reference的類型是A還是B。因此,只能夠在運(yùn)行時(shí),根據(jù)賦給輸入變量“reference”的對(duì)象的類型(例如,A或者B的實(shí)例)來(lái)決定調(diào)用方法#3還是方法#4
泛型(又稱類型檢驗(yàn)):這個(gè)是發(fā)生在編譯期的。編譯器負(fù)責(zé)檢查程序中類型的正確性,然后把使用了泛型的代碼翻譯或者重寫成可以執(zhí)行在當(dāng)前JVM上的非泛型代碼。這個(gè)技術(shù)被稱為“類型擦除“。
換句話來(lái)說(shuō),編譯器會(huì)擦除所有在尖括號(hào)里的類型信息,來(lái)保證和版本1.4.0或者更早版本的JRE的兼容性。
1List myList = new ArrayList(10);
編譯后成為了:
1List myList = new ArrayList(10);
異常(Exception):你可以使用運(yùn)行時(shí)異常或者編譯時(shí)異常。
運(yùn)行時(shí)異常(RuntimeException)也稱作未檢測(cè)的異常(unchecked exception),這表示這種異常不需要編譯器來(lái)檢測(cè)。
RuntimeException是所有可以在運(yùn)行時(shí)拋出的異常的父類。一個(gè)方法除要捕獲異常外,如果它執(zhí)行的時(shí)候可能會(huì)拋出
RuntimeException的子類,那么它就不需要用throw語(yǔ)句來(lái)聲明拋出的異常。
例如:NullPointerException,ArrayIndexOutOfBoundsException,等等
受檢查異常(checked exception)都是編譯器在編譯時(shí)進(jìn)行校驗(yàn)的,通過(guò)throws語(yǔ)句或者try{}cathch{} 語(yǔ)句塊來(lái)處理檢測(cè)異常。編譯器會(huì)分析哪些異常會(huì)在執(zhí)行一個(gè)方法或者構(gòu)造函數(shù)的時(shí)候拋出。
希望本篇文章對(duì)您有所幫助
相關(guān)文章
mybatis中association標(biāo)簽的使用解讀
這篇文章主要介紹了mybatis中association標(biāo)簽的使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05SpringBoot+Elasticsearch實(shí)現(xiàn)數(shù)據(jù)搜索的方法詳解
Elasticsearch是一個(gè)基于Lucene的搜索服務(wù)器。它提供了一個(gè)分布式多用戶能力的全文搜索引擎,基于RESTful?web接口。本文將利用SpringBoot整合Elasticsearch實(shí)現(xiàn)海量級(jí)數(shù)據(jù)搜索,需要的可以參考一下2022-05-05JAVA中使用FileWriter寫數(shù)據(jù)到文本文件步驟詳解
這篇文章主要介紹了JAVA中使用FileWriter寫數(shù)據(jù)到文本文件步驟詳解,FileWriter類提供了多種寫入字符的方法,包括寫入單個(gè)字符、寫入字符數(shù)組和寫入字符串等,它還提供了一些其他的方法,如刷新緩沖區(qū)、關(guān)閉文件等,需要的朋友可以參考下2023-10-10