日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

java類生命周期

系統(tǒng) 3161 0

文章摘抄至 http://www.2cto.com/kf/201204/129386.html
?
首先來了解一下jvm(java虛擬機(jī))中的幾個比較重要的內(nèi)存區(qū)域,這幾個區(qū)域在java類的生命周期中扮演著比較重要的角色:
方法區(qū):在java的虛擬機(jī)中有一塊專門用來存放已經(jīng)加載的類信息、常量、靜態(tài)變量以及方法代碼的內(nèi)存區(qū)域,叫做方法區(qū)。
常量池:常量池是方法區(qū)的一部分,主要用來存放常量和類中的符號引用等信息。
堆區(qū): 用于存放類的對象實(shí)例 。
棧區(qū):也叫java虛擬機(jī)棧,是由一個一個的棧幀組成的后進(jìn)先出的棧式結(jié)構(gòu),棧楨中 存放方法運(yùn)行時產(chǎn)生的局部變量、方法出口等信息 。 當(dāng)調(diào)用一個方法時,虛擬機(jī)棧中就會創(chuàng)建一個棧幀存放這些數(shù)據(jù),當(dāng)方法調(diào)用完成時,棧幀消失 ,如果方法中調(diào)用了其他方法,則繼續(xù)在棧頂創(chuàng)建新的棧楨。
? ? ? ? 除了以上四個內(nèi)存區(qū)域之外,jvm中的運(yùn)行時內(nèi)存區(qū)域還包括本地方法棧和程序計數(shù)器,這兩個區(qū)域與java類的生命周期關(guān)系不是很大,在這里就不說了,感興趣的朋友可以自己百度一下。
?
類的生命周期
? ? ? ? 當(dāng)我們編寫一個java的源文件后,經(jīng)過編譯會生成一個后綴名為class的文件,這種文件叫做字節(jié)碼文件,只有這種字節(jié)碼文件才能夠在java虛擬機(jī)中運(yùn)行,java類的生命周期就是指一個class文件從加載到卸載的全過程。

?

? java類生命周期

?

加載
? ? 在java中,我們經(jīng)常會接觸到一個詞——類加載,它和這里的加載并不是一回事,通常我們說類加載指的是類的生命周期中加載、連接、初始化三個階段。在加載階段,java虛擬機(jī)會做什么工作呢?其實(shí)很簡單,就是找到需要加載的類并把類的信息加載到j(luò)vm的方法區(qū)中,然后在堆區(qū)中實(shí)例化一個java.lang.Class對象,作為方法區(qū)中這個類的信息的入口。


? ? 類的加載方式比較靈活,我們最常用的加載方式有兩種,一種是根據(jù)類的全路徑名找到相應(yīng)的class文件,然后從class文件中讀取文件內(nèi)容;另一種是從jar文件中讀取。另外,還有下面幾種方式也比較常用:

從網(wǎng)絡(luò)中獲取:比如10年前十分流行Applet。根據(jù)一定的規(guī)則實(shí)時生成,比如設(shè)計模式中的動態(tài)代理模式,就是根據(jù)相應(yīng)的類自動生成它的代理類。從非class文件中獲取,其實(shí)這與直接從class文件中獲取的方式本質(zhì)上是一樣的,這些非class文件在jvm中運(yùn)行之前會被轉(zhuǎn)換為可被jvm所識別的字節(jié)碼文件。


? ? 對于加載的時機(jī),各個虛擬機(jī)的做法并不一樣,但是有一個原則,就是當(dāng)jvm“預(yù)期”到一個類將要被使用時,就會在使用它之前對這個類進(jìn)行加載。比如說,在一段代碼中出現(xiàn)了一個類的名字,jvm在執(zhí)行這段代碼之前并不能確定這個類是否會被使用到,于是,有些jvm會在執(zhí)行前就加載這個類,而有些則在真正需要用的時候才會去加載它,這取決于具體的jvm實(shí)現(xiàn)。我們常用的hotspot虛擬機(jī)是采用的后者,就是說當(dāng)真正用到一個類的時候才對它進(jìn)行加載。


? ? 加載階段是類的生命周期中的第一個階段,加載階段之后,是連接階段。有一點(diǎn)需要注意,就是有時連接階段并不會等加載階段完全完成之后才開始,而是交叉進(jìn)行,可能一個類只加載了一部分之后,連接階段就已經(jīng)開始了。但是這兩個階段總的開始時間和完成時間總是固定的:加載階段總是在連接階段之前開始,連接階段總是在加載階段完成之后完成。

?
連接
? ? 連接階段比較復(fù)雜,一般會跟加載階段和初始化階段交叉進(jìn)行,這個階段的主要任務(wù)就是做一些加載后的驗(yàn)證工作以及一些初始化前的準(zhǔn)備工作,可以細(xì)分為三個步驟:驗(yàn)證、準(zhǔn)備和解析。


? ? 驗(yàn)證 :當(dāng)一個類被加載之后,必須要驗(yàn)證一下這個類是否合法,比如這個類是不是符合字節(jié)碼的格式、變量與方法是不是有重復(fù)、數(shù)據(jù)類型是不是有效、繼承與實(shí)現(xiàn)是否合乎標(biāo)準(zhǔn)等等??傊?,這個階段的目的就是保證加載的類是能夠被jvm所運(yùn)行。


? ? 準(zhǔn)備 :準(zhǔn)備階段的工作就是為類的靜態(tài)變量分配內(nèi)存并設(shè)為jvm默認(rèn)的初值,對于非靜態(tài)的變量,則不會為它們分配內(nèi)存。有一點(diǎn)需要注意,這時候,靜態(tài)變量的初值為jvm默認(rèn)的初值,而不是我們在程序中設(shè)定的初值。jvm默認(rèn)的初值是這樣的:

? ? A) 基本類型(int、long、short、char、byte、boolean、float、double)的默認(rèn)值為0。
? ? B) 引用類型的默認(rèn)值為null。
? ? C) 常量的默認(rèn)值為我們程序中設(shè)定的值,比如我們在程序中定義final static int a = 100,則準(zhǔn)備階段中a的初值就是100。


? ? 解析 :這一階段的任務(wù)就是把常量池中的符號引用轉(zhuǎn)換為直接引用。那么什么是符號引用,什么又是直接引用呢?我們來舉個例子:我們要找一個人,我們現(xiàn)有的信息是這個人的身份證號是1234567890。只有這個信息我們顯然找不到這個人,但是通過公安局的身份系統(tǒng),我們輸入1234567890這個號之后,就會得到它的全部信息:比如安徽省黃山市余暇村18號張三,通過這個信息我們就能找到這個人了。這里,123456790就好比是一個符號引用,而安徽省黃山市余暇村18號張三就是直接引用。在內(nèi)存中也是一樣,比如我們要在內(nèi)存中找一個類里面的一個叫做show的方法,顯然是找不到。但是在解析階段,jvm就會把show這個名字轉(zhuǎn)換為指向方法區(qū)的的一塊內(nèi)存地址,比如c17164,通過c17164就可以找到show這個方法具體分配在內(nèi)存的哪一個區(qū)域了。這里show就是符號引用,而c17164就是直接引用。 在解析階段,jvm會將所有的類或接口名、字段名、方法名轉(zhuǎn)換為具體的內(nèi)存地址

? ? ? ? 連接階段完成之后會根據(jù)使用的情況(直接引用還是被動引用)來選擇是否對類進(jìn)行初始化。
?
初始化
? ? 如果一個類被直接引用,就會觸發(fā)類的初始化。在java中,直接引用的情況有
? ? 1、通過new關(guān)鍵字實(shí)例化對象、讀取或設(shè)置類的靜態(tài)變量、調(diào)用類的靜態(tài)方法。
? ? 2、通過反射方式執(zhí)行以上三種行為。
? ? 3、初始化子類的時候,會觸發(fā)父類的初始化。
? ? 4、作為程序入口直接運(yùn)行時(也就是直接調(diào)用main方法)。
? ? 除了以上四種情況,其他使用類的方式叫做被動引用,而被動引用不會觸發(fā)類的初始化
?
類的初始化過程是這樣的:按照順序自上而下運(yùn)行類中的變量賦值語句和靜態(tài)語句,如果有父類,則首先按照順序運(yùn)行父類中的變量賦值語句和靜態(tài)語句。先看一個例子,首先建兩個類用來顯示賦值操作

?

      
        public class Field1{ 
    public Field1(){ 
        System.out.println("Field1構(gòu)造方法"); 
    } 
}
      
    
?

?

      
        public class Field2{ 
    public Field2(){ 
        System.out.println("Field2構(gòu)造方法"); 
    } 
} 
      
    
?
      
        class InitClass2{ 
    static{ 
        System.out.println("運(yùn)行父類靜態(tài)代碼"); 
    } 
    public static Field1 f1 = new Field1(); 
    public static Field1 f2;  
} 
      
    
??
      
        class SubInitClass2 extends InitClass2{ 
    static{ 
        System.out.println("運(yùn)行子類靜態(tài)代碼"); 
    } 
    public static Field2 f2 = new Field2(); 
} 
      
    
?
      
        public class Test2 { 
    public static void main(String[] args) throws ClassNotFoundException{ 
        new SubInitClass2(); 
    } 
}
      
    
?運(yùn)行結(jié)果:

運(yùn)行父類靜態(tài)代碼

Field1構(gòu)造方法

運(yùn)行子類靜態(tài)代碼

Field2構(gòu)造方法

?
? ? 在類的初始化階段,只會初始化與類相關(guān)的賦值語句和靜態(tài)語句,也就是有static關(guān)鍵字修飾的信息,沒有static修飾的賦值語句和靜態(tài)語句在實(shí)例化對象的時候才會運(yùn)行。
?
使用
? ? 類的使用包括主動引用和被動引用,主動引用在初始化的章節(jié)中已經(jīng)說過了,下面我們主要來說一下被動引用:
? ? 引用父類的靜態(tài)字段,只會引起父類的初始化,而不會引起子類的初始化 。
? ? 定義類數(shù)組,不會引起類的初始化 。
? ? 引用類的常量,不會引起類的初始化 。

      
        class InitClass{ 
    static { 
        System.out.println("初始化InitClass"); 
    } 
    public static String a = null; 
    public final static String b = "b"; 
    public static void method(){} 
} 
      
    

?

      
        class SubInitClass extends InitClass{ 
    static { 
        System.out.println("初始化SubInitClass"); 
    } 
} 
      
    

?

      
        public class Test2 { 
    public static void main(String[] args) throws Exception{ 
    	// 引用父類的靜態(tài)字段,只會引起父類初始化,而不會引起子類的初始化  
        //String a = SubInitClass.a;
    	// 使用類的常量不會引起類的初始化  
        // String b = InitClass.b;
        // 定義類數(shù)組不會引起類的初始化  
        SubInitClass[] sc = new SubInitClass[10];
    } 
}
      
    

?
最后總結(jié)一下使用階段: 使用階段包括主動引用和被動引用,主動飲用會引起類的初始化,而被動引用不會引起類的初始化
當(dāng)使用階段完成之后,java類就進(jìn)入了卸載階段

?
卸載
? ? 關(guān)于類的卸載,筆者在單例模式討論篇:單例模式與垃圾回收一文中有過描述,在類使用完之后,如果有下面的情況,類就會被卸載:

該類所有的實(shí)例都已經(jīng)被回收,也就是java堆中不存在該類的任何實(shí)例。加載該類的ClassLoader已經(jīng)被回收。該類對應(yīng)的java.lang.Class對象沒有任何地方被引用,無法在任何地方通過反射訪問該類的方法。
? ? 如果以上三個條件全部滿足,jvm就會在方法區(qū)垃圾回收的時候?qū)︻愡M(jìn)行卸載,類的卸載過程其實(shí)就是在方法區(qū)中清空類信息,java類的整個生命周期就結(jié)束了。

總結(jié)
? ? 做java的朋友對于對象的生命周期可能都比較熟悉,對象基本上都是在jvm的堆區(qū)中創(chuàng)建,在創(chuàng)建對象之前,會觸發(fā)類加載(加載、連接、初始化),當(dāng)類初始化完成后,根據(jù)類信息在堆區(qū)中實(shí)例化類對象,初始化非靜態(tài)變量、非靜態(tài)代碼以及默認(rèn)構(gòu)造方法,當(dāng)對象使用完之后會在合適的時候被jvm垃圾收集器回收。讀完本文后我們知道,對象的生命周期只是類的生命周期中使用階段的主動引用的一種情況(即實(shí)例化類對象)。而類的整個生命周期則要比對象的生命周期長的多。

?

java類生命周期


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦?。。?/p>

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 康乐县| 新津县| 康乐县| 石狮市| 尉犁县| 河东区| 浦城县| 辛集市| 渝北区| 长子县| 九龙坡区| 黎城县| 乳山市| 商南县| 长寿区| 唐海县| 尖扎县| 涞水县| 临城县| 平泉县| 崇仁县| 郓城县| 周至县| 襄垣县| 哈尔滨市| 中卫市| 沾化县| 仁布县| 侯马市| 清河县| 绥化市| 长武县| 盖州市| 乐安县| 陇西县| 江北区| 马龙县| 涞源县| 麟游县| 增城市| 招远市|