电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

通過(guò)實(shí)例解析Java class文件編譯加載過(guò)程

瀏覽:32日期:2022-08-28 10:34:03

一、Java從編碼到執(zhí)行

首先我們來(lái)看一下Java是如何從編碼到執(zhí)行的呢? 我們有一個(gè)x.java文件通過(guò)執(zhí)行javac命令可以變成x.class文件,當(dāng)我們調(diào)用Java命令的時(shí)候class文件會(huì)被裝載到內(nèi)存中,這個(gè)過(guò)程叫做classloader。一般情況下我們自己寫代碼的時(shí)候會(huì)用到Java的類庫(kù),所以在加載的時(shí)候也會(huì)把Java類庫(kù)相關(guān)的類也加載到內(nèi)存中。裝載完成之后會(huì)調(diào)用字節(jié)碼解釋器和JIT即時(shí)編譯器來(lái)進(jìn)行解釋和編譯,編譯完之后由執(zhí)行引擎開始執(zhí)行,執(zhí)行引擎下面對(duì)應(yīng)的就是操作系統(tǒng)硬件了。下圖是大體的流程:

通過(guò)實(shí)例解析Java class文件編譯加載過(guò)程

Java叫做跨平臺(tái)的語(yǔ)言,JVM可以稱之為跨語(yǔ)言的平臺(tái);

有個(gè)問(wèn)題:java是解釋執(zhí)行還是編譯執(zhí)行?答:解釋和編譯是可以混合的,特別常用的代碼或則是代碼用到的次數(shù)特別多的時(shí)候,會(huì)把一個(gè)即時(shí)編譯做成本地編譯,這樣會(huì)很大程度上的提高效率。

Java虛擬機(jī)是如何做到這么多語(yǔ)言都可以在上面運(yùn)行,關(guān)鍵在于class文件,任何語(yǔ)言只要能編譯成class文件,并且符合class文件的規(guī)范你就可以放在Java虛擬機(jī)上去運(yùn)行。

二、詳解class文件的加載過(guò)程

接下來(lái)主要講的是一個(gè)class文件是怎么從硬盤上到內(nèi)存中,并開始執(zhí)行的。

類加載主要有三個(gè)過(guò)程:loading 、linking 、initializing;其中l(wèi)inking又分為三個(gè)步驟:verification 、preparation 、resolution;

通過(guò)實(shí)例解析Java class文件編譯加載過(guò)程

1、首先Loading是什么意思呢?是把一個(gè)class問(wèn)價(jià)load到內(nèi)存中去;

2、接下來(lái)是Linking分為了三小步:

verification 是用來(lái)校驗(yàn)加載進(jìn)來(lái)的class文件是否符合class文件標(biāo)準(zhǔn),如果不符合直接就會(huì)被拒絕了; preparation 是將class文件靜態(tài)變量賦默認(rèn)值而不是初始值,例如static int i =8;這個(gè)步驟并不是將i賦值為8,而是賦值為默認(rèn)值0; resolution 是把class文件常量池中用到的符號(hào)引用轉(zhuǎn)換成直接內(nèi)存地址,可以訪問(wèn)到的內(nèi)容;

3、initializing 成為初始化,靜態(tài)變量在這個(gè)時(shí)候才會(huì)被賦值為初始值;

下面為類加載過(guò)程的簡(jiǎn)化圖:

通過(guò)實(shí)例解析Java class文件編譯加載過(guò)程

類加載器的加載過(guò)程是分成不同的層次來(lái)加載的,不同的類加載器來(lái)加載不同的class文件, Bootstrap >Extension>Application>Custom(自定義類加載器)

1、第一個(gè)類加載器的層次為:Bootstrap 稱為啟動(dòng)類加載器,是Java類加載層次中最頂層的類加載器,負(fù)責(zé)加載JDK中的核心類庫(kù)。

2、第二個(gè)類加載器的層次為:Extension 是用來(lái)加載擴(kuò)展類的,主要負(fù)責(zé)加載Java的擴(kuò)展類庫(kù),默認(rèn)加載JAVA_HOME/jre/lib/ext/目錄下的所有jar包。

3、第三個(gè)類加載器的層次為:Application又稱為系統(tǒng)類加載器,負(fù)責(zé)在JVM啟動(dòng)時(shí),加載來(lái)自在命令java中的classpath或者java.class.path系統(tǒng)屬性或者CLASSPATH操作系統(tǒng)屬性所指定的JAR類包和類路徑。

4、第三個(gè)類加載器的層次為:CustomClassLoader(自定義加載器)

package com.example.demo.classloader;public class ClassLoaderScope { public static void main(String[] args) { System.out.println('-------------------Bootstrap加載類-------------------'); String property = System.getProperty('sun.boot.class.path'); String s = property.replaceAll(';', System.lineSeparator()); System.out.println(s); System.out.println('-------------------Ext加載類-------------------'); String property1 = System.getProperty('java.ext.dirs'); String s1 = property1.replaceAll(';', System.lineSeparator()); System.out.println(s1); System.out.println('-------------------App加載類-------------------'); String property2 = System.getProperty('java.class.path'); String s2 = property2.replaceAll(';', System.lineSeparator()); System.out.println(s2); }} /**輸出結(jié)果只截取了部分*/ //E:JDKjdk1.8jrelibresources.jar //E:JDKjdk1.8jrelibrt.jar //E:JDKjdk1.8jrelibsunrsasign.jar //E:JDKjdk1.8jrelibjsse.jar //E:JDKjdk1.8jrelibjce.jar //E:JDKjdk1.8jrelibcharsets.jar //E:JDKjdk1.8jrelibjfr.jar //E:JDKjdk1.8jreclasses //---------------------------------------------- //E:JDKjdk1.8jrelibext //C:WindowsSunJavalibext //---------------------------------------------- //E:JDKjdk1.8jrelibcharsets.jar //E:JDKjdk1.8jrelibdeploy.jar //E:JDKjdk1.8jrelibextaccess-bridge-64.jar //E:JDKjdk1.8jrelibextcldrdata.jar //E:JDKjdk1.8jrelibextdnsns.jar //E:JDKjdk1.8jrelibextjaccess.jar //E:JDKjdk1.8jrelibextjfxrt.jar

特別注意一點(diǎn)這個(gè)的層級(jí)關(guān)系并沒有繼承的關(guān)系在里面,只是單單純純的語(yǔ)法上的繼承;

下圖為類加載的一個(gè)全過(guò)程:

用比較通俗的話來(lái)解釋這個(gè)過(guò)程,當(dāng)有一個(gè)類需要被加載時(shí),首先要判斷這個(gè)類是否已經(jīng)被加載到內(nèi)存,判斷加載與否的過(guò)程是有順序的,如果有自己定義的類加載器,會(huì)先到custom class loader 的cache(緩存)中去找是否已經(jīng)加載,若已加載直接返回結(jié)果,否則到App的cache中查找,如果已經(jīng)存在直接返回,如果不存在,到Extension中查找,存在直接返回,不存在繼續(xù)向父加載器中尋找直到Bootstrap頂層,如果依然沒找到,那就是沒有加載器加載過(guò)這個(gè)類,需要委派對(duì)應(yīng)的加載器來(lái)加載,先看看這個(gè)類是否在自己的加載范圍內(nèi),如果是直接加載返回結(jié)果,若不是繼續(xù)向下委派,以此類推直到最下級(jí),如果最終也沒能加載,就會(huì)直接拋異常ClassNotFoundException,這就是雙親委派模式。

通過(guò)實(shí)例解析Java class文件編譯加載過(guò)程

理解雙親委派模式:

1、父加載器:不是類加載器的加載器,也不是類加載器的父類加載器(此處意思是沒有父類與子類之間的繼承關(guān)系)。

package com.example.demo.classloader;/** * 驗(yàn)證了父加載器不是加載器的加載器 */public class ParentAndChild { public static void main(String[] args) { //AppClassLoader ClassLoader classLoader = ParentAndChild.class.getClassLoader(); System.out.println(classLoader); //null 這里AppClassLoader的加載器不是ExtClassLoader 而是Bootstrap ClassLoader appclassLoader = ParentAndChild.class.getClassLoader().getClass().getClassLoader(); System.out.println(appclassLoader); //ExtClassLoader AppClassLoader的父加載器是ExtClassLoader ClassLoader parent = ParentAndChild.class.getClassLoader().getParent(); System.out.println(parent); //null ClassLoader parentparent = ParentAndChild.class.getClassLoader().getParent().getParent(); System.out.println(parentparent); //null ClassLoader parentparentparent = ParentAndChild.class.getClassLoader().getParent().getParent().getParent(); System.out.println(parentparent); /**輸出結(jié)果*/ //sun.misc.Launcher$AppClassLoader@18b4aac2 //null //sun.misc.Launcher$ExtClassLoader@23fc625e //null //Exception in thread 'main' java.lang.NullPointerException at com.example.demo.classloader.ParentAndChild.main(ParentAndChild.java:22) }}

2、雙親委派:其工作原理的是,如果一個(gè)類加載器收到了類加載請(qǐng)求,并不會(huì)直接去加載,而是自下而上的向頂層類加載器查找是否已經(jīng)被加載了,如果被加載就不用進(jìn)行加載,如果未被加載過(guò),則會(huì)自上而下的檢查是否屬于自己加載的范圍,如果屬于則加載,如果不屬于則向下委托,直到類被加載進(jìn)來(lái)才能叫做成功,如果加載不成功就會(huì)拋異常classnotfoundexeption,這就叫做雙親委派。

3、為什么要搞雙親委派模式?

主要是為了安全,這里可以使用反證法,如果任何類加載器都可以把class加載到內(nèi)存中,我們就可以自定義類加載器來(lái)加載Java.lang.string。在打包時(shí)可以把密碼存儲(chǔ)為String對(duì)象,偷偷摸摸的把密碼發(fā)送到自己的郵箱,這樣會(huì)造成安全問(wèn)題。

三、自定義類加載器

package com.example.demo.classloader;public class ClassLoaderByHand { public static void main(String[] args) throws ClassNotFoundException { Class<?> clazz = ClassLoaderByHand.class.getClassLoader().loadClass('com.example.demo.threaddemo.juc_002.Account'); String name = clazz.getName(); System.out.println(name); }} /** * 輸出結(jié)果 */ //com.example.demo.threaddemo.juc_002.Account

代碼運(yùn)行結(jié)果可以看出,就是你要加載一個(gè)類你只要調(diào)用classLoader中的loadClass()方法就能把這個(gè)類加載到內(nèi)存中,加載完成之后會(huì)給你返回一個(gè)Class類的對(duì)象。

在硬盤上找到這個(gè)類的源碼,把它load到內(nèi)存,與此同時(shí)生成一個(gè)Class對(duì)象,上述的小程序是通過(guò)ClassLoaderByHand 找到他的加載器AppClassLoader 然后調(diào)用它的loadClass()方法,讓它幫我們把Account類加載進(jìn)來(lái),返回一個(gè)clazz對(duì)象,使用clazz.getName()方法正常返回Account類。

什么時(shí)候我們需要自己定義去加載一個(gè)類?

熱部署時(shí)就是先把之前加載的類給干掉 ,然后使用的自定義類加載器來(lái)進(jìn)行重新加載

spring的動(dòng)態(tài)代理,一個(gè)新的class 當(dāng)需要的時(shí)候就會(huì)把它load到內(nèi)存中

我們還是來(lái)看一下源碼吧,加載過(guò)程最主要的還是ClassLoader中的loaderClass()方法:

結(jié)合上面給的類加載過(guò)程的圖解一起看會(huì)更容易一些;

protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { /** * 在加載之前先調(diào)用findLoadedClass()方法查看是否已經(jīng)加載過(guò)此類 * 若加載過(guò) 返回該對(duì)象 * 如果未加載則返回null 進(jìn)行下一步 */ // First, check if the class has already been loaded Class<?> c = findLoadedClass(name); if (c == null) {long t0 = System.nanoTime();try { //判斷有無(wú)父加載器 如果不為空說(shuō)明還未到頂層Bootstrap遞歸調(diào)用loadClass() if (parent != null) { c = parent.loadClass(name, false); } else { //如果沒有父加載器說(shuō)明調(diào)用的加載器為Bootstrap Class Loader, 在此加載器內(nèi)存中查找是否已經(jīng)加載 c = findBootstrapClassOrNull(name); }} catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader}//若以上的操作都沒成功加載此類if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); //調(diào)用自己的findClass() c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment();} } if (resolve) {resolveClass(c); } return c; } }

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持好吧啦網(wǎng)。

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 江西自考网| 浩方智通 - 防关联浏览器 - 跨境电商浏览器 - 云雀浏览器 | 天津中都白癜风医院_天津白癜风医院_天津治疗白癜风 | 智能气瓶柜(大型气瓶储存柜)百科 | 硬度计_影像测量仪_维氏硬度计_佛山市精测计量仪器设备有限公司厂家 | 台式核磁共振仪,玻璃软化点测定仪,旋转高温粘度计,测温锥和测温块-上海麟文仪器 | 广东燎了网络科技有限公司官网-网站建设-珠海网络推广-高端营销型外贸网站建设-珠海专业h5建站公司「了了网」 | 伟秀电气有限公司-10kv高低压开关柜-高低压配电柜-中置柜-充气柜-欧式箱变-高压真空断路器厂家 | PCB接线端子_栅板式端子_线路板连接器_端子排生产厂家-置恒电气 喷码机,激光喷码打码机,鸡蛋打码机,手持打码机,自动喷码机,一物一码防伪溯源-恒欣瑞达有限公司 假肢-假肢价格-假肢厂家-河南假肢-郑州市力康假肢矫形器有限公司 | 深圳展厅设计_企业展馆设计_展厅设计公司_数字展厅设计_深圳百艺堂 | 间苯二酚,间苯二酚厂家-淄博双和化工| 「安徽双凯」自动售货机-无人售货机-成人用品-自动饮料食品零食售货机 | 粘度计,数显粘度计,指针旋转粘度计 | 大通天成企业资质代办_承装修试电力设施许可证_增值电信业务经营许可证_无人机运营合格证_广播电视节目制作许可证 | 千斤顶,液压千斤顶-力良企业,专业的液压千斤顶制造商,shliliang.com | 网带通过式抛丸机,,网带式打砂机,吊钩式,抛丸机,中山抛丸机生产厂家,江门抛丸机,佛山吊钩式,东莞抛丸机,中山市泰达自动化设备有限公司 | 通风气楼_通风天窗_屋顶风机-山东美创通风设备有限公司 | 电脑知识|软件|系统|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网 | 震动筛选机|震动分筛机|筛粉机|振筛机|振荡筛-振动筛分设备专业生产厂家高服机械 | 深圳标识制作公司-标识标牌厂家-深圳广告标识制作-玟璟广告-深圳市玟璟广告有限公司 | 定制异形重型钢格栅板/钢格板_定做踏步板/排水沟盖板_钢格栅板批发厂家-河北圣墨金属制品有限公司 | 流量卡中心-流量卡套餐查询系统_移动电信联通流量卡套餐大全 | 精密钢管,冷拔精密无缝钢管,精密钢管厂,精密钢管制造厂家,精密钢管生产厂家,山东精密钢管厂家 | 昆山PCB加工_SMT贴片_PCB抄板_线路板焊接加工-昆山腾宸电子科技有限公司 | 柴油发电机组_柴油发电机_发电机组价格-江苏凯晨电力设备有限公司 | 泥浆在线密度计厂家-防爆数字压力表-膜盒-远传压力表厂家-江苏大亚自控设备有限公司 | 广州办公室设计,办公室装修,写字楼设计,办公室装修公司_德科 | 商秀—企业短视频代运营_抖音企业号托管| 【铜排折弯机,钢丝折弯成型机,汽车发泡钢丝折弯机,线材折弯机厂家,线材成型机,铁线折弯机】贝朗折弯机厂家_东莞市贝朗自动化设备有限公司 | 南京和瑞包装有限公司| 喷砂机厂家_自动喷砂机生产_新瑞自动化喷砂除锈设备 | 螺杆式冷水机-低温冷水机厂家-冷冻机-风冷式-水冷式冷水机-上海祝松机械有限公司 | 创客匠人-让IP变现不走弯路| 杭州货架订做_组合货架公司_货位式货架_贯通式_重型仓储_工厂货架_货架销售厂家_杭州永诚货架有限公司 | 纯化水设备-纯水设备-超纯水设备-[大鹏水处理]纯水设备一站式服务商-东莞市大鹏水处理科技有限公司 | 顺辉瓷砖-大国品牌-中国顺辉| 地磅-电子地磅维修-电子吊秤-汽车衡-无人值守系统-公路治超-鹰牌衡器 | 环氧乙烷灭菌器_压力蒸汽灭菌器_低温等离子过氧化氢灭菌器 _低温蒸汽甲醛灭菌器_清洗工作站_医用干燥柜_灭菌耗材-环氧乙烷灭菌器_脉动真空压力蒸汽灭菌器_低温等离子灭菌设备_河南省三强医疗器械有限责任公司 | 泰国专线_泰国物流专线_广州到泰国物流公司-泰廊曼国际 | 软启动器-上海能曼电气有限公司| 流变仪-热分析联用仪-热膨胀仪厂家-耐驰科学仪器商贸 |