Java代碼的執(zhí)行機(jī)制
在JVM中執(zhí)行的是編譯過(guò)后的Class文件里覆,classloader類加載器來(lái)負(fù)責(zé)加載class文件,那么首先要了解的就是java如何將java文件編譯為class文件的宝踪?
Java代碼的編譯機(jī)制
編譯過(guò)程
java文件->分析和輸入到符號(hào)表(parse and enter)->注解處理(annotation processing)->語(yǔ)義分析和生成class文件(analyse and generate)->class文件
簡(jiǎn)單歸結(jié)為三個(gè)步驟:
1.分析和輸入到符號(hào)表
parse過(guò)程蔼紧,一是詞法分析俭嘁,將代碼字符串轉(zhuǎn)化成token序列(Token.EQ(name:=));二是,語(yǔ)法分析肴颊,將token抽象成語(yǔ)法樹(shù)氓栈;
enter過(guò)程,將符號(hào)輸入到符號(hào)表婿着,其實(shí)也就是添加累的一些構(gòu)造器屬性等授瘦,歸入類中。
2.注解處理
就是處理用戶自定義的注解竟宋,簡(jiǎn)化代碼的編寫提完,在注解處理過(guò)程結(jié)束后,會(huì)在此進(jìn)入分析和輸入符號(hào)表的過(guò)程中丘侠。
3.語(yǔ)義分析和生成class文件
語(yǔ)義分析就是將抽象語(yǔ)法樹(shù)中的名字表達(dá)式等元素與變量方法類型等聯(lián)系到一起徒欣,檢查變量是否聲明,是否拋出一場(chǎng)蜗字,推導(dǎo)范型類型打肝,自動(dòng)拆箱裝箱等。
然后將語(yǔ)法書(shū)轉(zhuǎn)化為字節(jié)碼挪捕,做少量的代碼轉(zhuǎn)化粗梭,如 String相加轉(zhuǎn)換為stringbuffer等,最后從符號(hào)表生成為class文件级零。
1)詞法分析:讀取源代碼断医,一個(gè)字節(jié)一個(gè)字節(jié)的讀進(jìn)來(lái),找出這些詞法中我們定義的語(yǔ)言關(guān)鍵詞如:if妄讯、else孩锡、while等酷宵,識(shí)別哪些if是合法的哪些是不合法的亥贸。這個(gè)步驟就是詞法分析過(guò)程。
詞法分析的結(jié)果:就是從源代碼中找出了一些規(guī)范化的token流浇垦,就像人類語(yǔ)言中炕置,給你一句話你要分辨出哪些是一個(gè)詞語(yǔ),哪些是標(biāo)點(diǎn)符號(hào),哪些是動(dòng)詞朴摊,哪些是名詞默垄。
2)語(yǔ)法分析:就是對(duì)詞法分析中得到的token流進(jìn)行語(yǔ)法分析,這一步就是檢查這些關(guān)鍵詞組合在一起是不是符合Java語(yǔ)言規(guī)范甚纲。如if的后面是不是緊跟著一個(gè)布爾型判斷表達(dá)式口锭。
語(yǔ)法分析的結(jié)果:就是形成一個(gè)符合Java語(yǔ)言規(guī)定的抽象語(yǔ)法樹(shù),抽象語(yǔ)法樹(shù)是一個(gè)結(jié)構(gòu)化的語(yǔ)法表達(dá)形式介杆,它的作用是把語(yǔ)言的主要詞法用一個(gè)結(jié)構(gòu)化的形式組織在一起鹃操。這棵語(yǔ)法樹(shù)可以被后面按照新的規(guī)則再重新組織。
3)語(yǔ)義分析:語(yǔ)法分析完成之后也就不存在語(yǔ)法問(wèn)題了春哨,語(yǔ)義分析的主要工作就是把一些難懂的荆隘,復(fù)雜的語(yǔ)法轉(zhuǎn)化成更簡(jiǎn)單的語(yǔ)法。就如難懂的文言文轉(zhuǎn)化為大家都懂的白話文赴背,或者是注釋一下一些不懂的成語(yǔ)椰拒。
語(yǔ)義分析結(jié)果:就是將復(fù)雜的語(yǔ)法轉(zhuǎn)化為簡(jiǎn)單的語(yǔ)法,對(duì)應(yīng)到Java就是將foreach轉(zhuǎn)化為for循環(huán)凰荚,還有一些注釋等燃观。最后生成一棵抽象的語(yǔ)法樹(shù),這棵語(yǔ)法樹(shù)也就更接近目標(biāo)語(yǔ)言的語(yǔ)法規(guī)則浇揩。
4)字節(jié)碼生成:將會(huì)根據(jù)經(jīng)過(guò)注釋的抽象語(yǔ)法樹(shù)生成字節(jié)碼仪壮,也就是將一個(gè)數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)化為另外一個(gè)數(shù)據(jù)結(jié)構(gòu)。就像將所有的中文詞語(yǔ)翻譯成英文單詞后按照英文語(yǔ)法組裝文英文語(yǔ)句胳徽。代碼生成器的結(jié)果就是生成符合java虛擬機(jī)規(guī)范的字節(jié)碼积锅。
Java 代碼的類加載機(jī)制
類加載機(jī)制,就是將上面編譯的.class文件养盗,加載到JVM中缚陷,生成Class對(duì)象,之后就可以對(duì)Class進(jìn)行實(shí)例化和調(diào)用了往核。
JVM類加載過(guò)程劃為三個(gè)步驟:裝載箫爷,鏈接,初始化聂儒。裝載和鏈接就是將.class轉(zhuǎn)化為的字節(jié)碼轉(zhuǎn)化生成Class對(duì)象虎锚,初始化并不是加載類的時(shí)候必須觸發(fā)的,但是必須主動(dòng)適用對(duì)象前觸發(fā)衩婚。
- 裝載的過(guò)程就是通過(guò)完全限定名和類加載器來(lái)完成類的加載窜护。
- 鏈接的過(guò)程是對(duì)二進(jìn)制的字節(jié)碼進(jìn)行校驗(yàn),初始化裝載類中的靜態(tài)變量以及解析類里面的調(diào)用的接口非春。
- 初始化過(guò)程即執(zhí)行類中的靜態(tài)初始化代碼柱徙、構(gòu)造器代碼和靜態(tài)屬性的初始化缓屠,下面四種情況會(huì)觸發(fā)初始化過(guò)程:
1 調(diào)用了new;
2 反射調(diào)用了類中的方法护侮;
3 子類調(diào)用了初始化敌完;
4 jvm啟動(dòng)過(guò)程中指定的初始化類
JVM的類的加載是通過(guò)Classloader以及他的子類來(lái)完成的,Bootstrap Classloader->Extension Classloader->System Classloader ->User-Defined Classloader羊初。
- Bootstrap ClassLoader
這一部分是C++寫的滨溉,拿不到這個(gè)類的對(duì)象,不是ClassLoader的子類长赞,jdk啟動(dòng)的時(shí)候會(huì)初始化這個(gè)ClassLoader业踏,由這個(gè)加載類記載$JAVA_HOME中jre/lib/rt.jar里所有文件的加載,jar中包含了JAVA規(guī)范定義的所有接口和實(shí)現(xiàn)涧卵。 - Extension ClassLoader
加載擴(kuò)展功能的jar包勤家,比如dns工具jar包。 - System ClassLoader
JVM用這個(gè)加載器來(lái)加載啟動(dòng)參數(shù)Classpath中的jar包和目錄柳恐,JDK中對(duì)應(yīng)的類名為APPClassLoader伐脖。 - User-Defined ClassLoader
這個(gè)是開(kāi)發(fā)人員繼承ClassLoader抽象類自行實(shí)現(xiàn)的ClassLoader,自定義的ClassLoader可以用來(lái)加載一些非Classpat中的jar和目錄乐设,比如從網(wǎng)絡(luò)上下載的jar或者二進(jìn)制文件讼庇,也可以再加載之前對(duì)class文件做一些動(dòng)作,比如解密近尚。