深入java虛擬機(jī)
- 作者:新網(wǎng)
- 來(lái)源:新網(wǎng)
- 瀏覽:100
- 2018-05-14 10:24:35
類(lèi)加載器,顧名思義,類(lèi)加載器(class loader)用來(lái)加載 Java 類(lèi)到 Java 虛擬機(jī)中。一般來(lái)說(shuō),Java 虛擬機(jī)使用 Java 類(lèi)的方式如下:Java 源程序(.java 文件)在經(jīng)過(guò) Java 編譯器編譯之后就被轉(zhuǎn)換成 Java 字節(jié)代碼(.class 文件)。類(lèi)加載器負(fù)責(zé)讀取 Java 字節(jié)代碼,并轉(zhuǎn)換成 java.lang.Class類(lèi)的一個(gè)實(shí)例。
類(lèi)加載器,顧名思義,類(lèi)加載器(class loader)用來(lái)加載 Java 類(lèi)到 Java 虛擬機(jī)中。一般來(lái)說(shuō),Java 虛擬機(jī)使用 Java 類(lèi)的方式如下:Java 源程序(.java 文件)在經(jīng)過(guò) Java 編譯器編譯之后就被轉(zhuǎn)換成 Java 字節(jié)代碼(.class 文件)。類(lèi)加載器負(fù)責(zé)讀取 Java 字節(jié)代碼,并轉(zhuǎn)換成 java.lang.Class類(lèi)的一個(gè)實(shí)例。
<
div> 每個(gè)這樣的實(shí)例用來(lái)表示一個(gè) Java 類(lèi)。通過(guò)此實(shí)例的 newInstance()方法就可以創(chuàng)建出該類(lèi)的一個(gè)對(duì)象。實(shí)際的情況可能更加復(fù)雜,比如 Java 字節(jié)代碼可能是通過(guò)工具動(dòng)態(tài)生成的,也可能是通過(guò)網(wǎng)絡(luò)下載的?;旧纤械念?lèi)加載器都是 java.lang.ClassLoader類(lèi)的一個(gè)實(shí)例。其實(shí)我們研究類(lèi)加載器主要研究的就是類(lèi)的生命周期。
首先來(lái)了解一下jvm(java虛擬機(jī))中的幾個(gè)比較重要的內(nèi)存區(qū)域,這幾個(gè)區(qū)域在java類(lèi)的生命周期中扮演著比較重要的角色:
方法區(qū):在java的虛擬機(jī)中有一塊專(zhuān)門(mén)用來(lái)存放已經(jīng)加載的類(lèi)信息、常量、靜態(tài)變量以及方法代碼的內(nèi)存區(qū)域,叫做方法區(qū)。
常量池:常量池是方法區(qū)的一部分,主要用來(lái)存放常量和類(lèi)中的符號(hào)引用等信息。
堆區(qū):用于存放類(lèi)的對(duì)象實(shí)例。
棧區(qū):也叫java虛擬機(jī)棧,是由一個(gè)一個(gè)的棧幀組成的后進(jìn)先出的棧式結(jié)構(gòu),棧楨中存放方法運(yùn)行時(shí)產(chǎn)生的局部變量、方法出口等信息。當(dāng)調(diào)用一個(gè)方法時(shí),虛擬機(jī)棧中就會(huì)創(chuàng)建一個(gè)棧幀存放這些數(shù)據(jù),當(dāng)方法調(diào)用完成時(shí),棧幀消失,如果方法中調(diào)用了其他方法,則繼續(xù)在棧頂創(chuàng)建新的棧楨。
類(lèi)的生命周期
當(dāng)我們編寫(xiě)一個(gè)java的源文件后,經(jīng)過(guò)編譯會(huì)生成一個(gè)后綴名為class的文件,這種文件叫做字節(jié)碼文件,只有這種字節(jié)碼文件才能夠在java虛擬機(jī)中運(yùn)行,java類(lèi)的生命周期就是指一個(gè)class文件從加載到卸載的全過(guò)程。一個(gè)java類(lèi)的完整的生命周期會(huì)經(jīng)歷加載、連接、初始化、使用、和卸載五個(gè)階段,當(dāng)然也有在加載或者連接之后沒(méi)有被初始化就直接被使用的情況,這里我們主要來(lái)研究類(lèi)加載器所執(zhí)行的部分,也就是加載,鏈接和初始化。
下面我先簡(jiǎn)單看一下類(lèi)加載器所執(zhí)行的三部分的簡(jiǎn)單介紹
1、加載:查找并加載類(lèi)的二進(jìn)制數(shù)據(jù)
2、連接
–驗(yàn)證:確保被加載的類(lèi)的正確性
–準(zhǔn)備:為類(lèi)的靜態(tài)變量分配內(nèi)存,并將其初始化為默認(rèn)值
–解析:把類(lèi)中的符號(hào)引用轉(zhuǎn)換為直接引用
3、初始化:為類(lèi)的靜態(tài)變量賦予正確的初始值
從上邊我們可以看出類(lèi)的靜態(tài)變量賦了兩回值。這是為什么呢?原因是,在連接過(guò)程中時(shí)為靜態(tài)變量賦值為默認(rèn)值,也就是說(shuō),只要是你定義了靜態(tài)變量,不管你開(kāi)始給沒(méi)給它設(shè)置,我系統(tǒng)都為他初始化一個(gè)默認(rèn)值。到了初始化過(guò)程,系統(tǒng)就檢查是否用戶(hù)定義靜態(tài)變量時(shí)有沒(méi)有給設(shè)置初始化值,如果有就把靜態(tài)變量設(shè)置為用戶(hù)自己設(shè)置的初始化值,如果沒(méi)有還是讓靜態(tài)變量為初始化值
類(lèi)的加載、連接和初始化
類(lèi)的加載
類(lèi)的加載指的是將類(lèi)的.class文件中的二進(jìn)制數(shù)據(jù)讀入到內(nèi)存中,將其放在運(yùn)行時(shí)數(shù)據(jù)區(qū)的方法區(qū)內(nèi),然后在堆區(qū)創(chuàng)建一個(gè)java.lang.Class對(duì)象,用來(lái)封裝類(lèi)在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu) 。這里的class對(duì)象其實(shí)就像一面鏡子一樣,外面是類(lèi)的源程序,里面是class對(duì)象,它實(shí)時(shí)的反應(yīng)了類(lèi)的數(shù)據(jù)結(jié)構(gòu)和信息。
加載.class文件的方式
1、從本地系統(tǒng)中直接加載
2、通過(guò)網(wǎng)絡(luò)下載.class文件
3、從zip,jar等歸檔文件中加載.class文件
5、將Java源文件動(dòng)態(tài)編譯為.class文件
類(lèi)的加載過(guò)程
結(jié)論:
1、類(lèi)的加載的最終產(chǎn)品是位于堆區(qū)中的Class對(duì)象
2、Class對(duì)象封裝了類(lèi)在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu),并且向Java程序員提供了訪(fǎng)問(wèn)方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)的接口
Java虛擬機(jī)給我們提供了兩種類(lèi)加載器:
1、Java虛擬機(jī)自帶的加載器
1)根類(lèi)加載器(使用C++編寫(xiě),程序員無(wú)法在Java代碼中獲得該類(lèi))
2)擴(kuò)展加載器,使用Java代碼實(shí)現(xiàn)
3)系統(tǒng)加載器(應(yīng)用加載器),使用Java代碼實(shí)現(xiàn)
2、用戶(hù)自定義的類(lèi)加載器
java.lang.ClassLoader的子類(lèi)
用戶(hù)可以定制類(lèi)的加載方式