類加載機(jī)制與反射(一)

類的加載、連接和初始化

1.JVM和類

當(dāng)調(diào)用java命令運(yùn)行某個(gè)java程序時(shí)镀赌,該命令會(huì)啟動(dòng)一個(gè)java虛擬機(jī)進(jìn)程音念,不管該Java程序有多么復(fù)雜沪饺,該程序啟動(dòng)了多少個(gè)線程,它們都處于該java虛擬機(jī)進(jìn)程里闷愤。
當(dāng)系統(tǒng)出現(xiàn)以下幾種情況時(shí)整葡,JVM進(jìn)程將被終止:
(1)程序運(yùn)行到最后正常結(jié)束
(2)使用 Systerm.exit()或者 Runtime.getRuntime().exit()
(3)執(zhí)行過程中遇到未捕獲的異常或者錯(cuò)誤而結(jié)束
(4)程序所在平臺(tái)強(qiáng)制結(jié)束JVM進(jìn)程

例子:
A.java

package com.example;

public class A
{
    //類變量
    public static int a = 5;
    public static void main(String[] args)
    {
    }
}

AText.java


package com.example;

/**
 * Created by zhoujian on 2017/4/3.
 */

public class AText
{
    public static void main(String[] args)
    {
        A a = new A();
        a.a++;
        //運(yùn)行結(jié)果:6
        System.out.println(a.a);
    }
}

BText.java

package com.example;

/**
 * Created by zhoujian on 2017/4/3.
 */

public class BText
{
    public static void main(String[] args)
    {
        A b = new A();
        //運(yùn)行結(jié)果:5
        System.out.println(b.a);
    }
}

兩次運(yùn)行讥脐,處于不同的JVM中遭居,兩個(gè)JVM之間并不會(huì)共享數(shù)據(jù)

2.類的加載

當(dāng)程序使用某個(gè)類時(shí),如果該類該類還未被加載到內(nèi)存中旬渠,則系統(tǒng)會(huì)通過加載魏滚、連接和初始化這三個(gè)步驟來對(duì)該類進(jìn)行初始化。這三個(gè)步驟稱為類加載或類初始化

類加載指的是將類的class文件讀入內(nèi)存坟漱,并為之創(chuàng)建一個(gè)java.lang.Class對(duì)象

類的加載由類加載器完成鼠次,類加載器通常由JVM提供

通過不同的類加載器,可以從不同來源加載類的二進(jìn)制數(shù)據(jù)

  • 從本地系統(tǒng)加載class 文件
  • 從JAR包加載class文件
  • 通過網(wǎng)絡(luò)加載class文件
  • 把一個(gè)java 文件動(dòng)態(tài)編譯芋齿,并執(zhí)行加載

類加載器無需等到使用時(shí)才去加載該類腥寇,java 虛擬機(jī)規(guī)范允許系統(tǒng)預(yù)先加載某些類

3.類的連接

當(dāng)類被加載之后,系統(tǒng)為之生成一個(gè)對(duì)應(yīng)的Class 對(duì)象觅捆,接著將進(jìn)入連接階段赦役,連接階段負(fù)責(zé)把二進(jìn)制數(shù)據(jù)合并到JRE中。類連接又分為三個(gè)階段

  • 驗(yàn)證:用于檢驗(yàn)被加載的類是否有正確的內(nèi)部結(jié)構(gòu)栅炒,并和其他類協(xié)調(diào)一致
  • 準(zhǔn)備:類準(zhǔn)備階段負(fù)責(zé)為類的類變量分配內(nèi)存掂摔,并設(shè)置默認(rèn)初始值
  • 解析:將類的二進(jìn)制數(shù)據(jù)中的符號(hào)引用替換成直接引用

4.類的初始化

在類的初始化階段,虛擬機(jī)負(fù)責(zé)對(duì)類進(jìn)行初始化赢赊,主要是對(duì)類變量初始化乙漓。
在java類中對(duì)變量指定初始值有兩種方式:

  • 聲明類變量時(shí)指定初始值
  • 使用靜態(tài)初始化塊為類變量指定初始值

package com.example;

/**
 * Created by zhoujian on 2017/4/3.
 */

public class AText
{
    //聲明變量 b時(shí)指定初始值
    static int b = 2;
    static
    {
        //使用靜態(tài)初始化塊為變量b指定初始值
        b = 5;

    }


    public static void main(String[] args)
    {

        A a = new A();
        a.a++;
        System.out.println(a.a);
        System.out.println(AText.b);
    }
}

5.類初始化的時(shí)機(jī)

當(dāng) Java 程序首次通過下面6種方式來使用某個(gè)類或者接口,系統(tǒng)就會(huì)初始化該類或者接口

  • 創(chuàng)建類的實(shí)例
  • 調(diào)用某個(gè)類的方法(靜態(tài)方法)
  • 訪問某個(gè)類或接口的類變量释移,或者為該類變量賦值
  • 使用反射的方式來強(qiáng)制創(chuàng)建某個(gè)類或者接口對(duì)應(yīng)的 java.lang.Class 對(duì)象
  • 初始化某個(gè)類的子類叭披。那么該子類所有父類都會(huì)被初始化
  • 直接使用java.exe 命令來運(yùn)行某個(gè)主類

對(duì)于一個(gè)final 型的類變量,如果該類變量在編譯的時(shí)就可以確定下來玩讳,那么這個(gè)類變量相當(dāng)于“宏變量”涩蜘。java 編譯器會(huì)在編譯時(shí)直接把這個(gè)類變量出現(xiàn)的地方替換成它的值,因此即使程序使用該靜態(tài)類變量熏纯,也不會(huì)導(dǎo)致該類的初始化

package com.example;

public class MyTest
{

    static
    {
        //靜態(tài)初始化塊

    }

    //變量name可以在編譯的時(shí)候確定下來同诫,相當(dāng)于一個(gè)常量
    static final String name = "zhoujian";
    
    public static void main(String[] args)
    {
        //不會(huì)初始化MyTest類
        System.out.println(MyTest.name);
    }

}

當(dāng)使用ClassLoader 類的loadClass()方法來加載某個(gè)類時(shí),該方法只是加載類樟澜,并不會(huì)執(zhí)行該類的初始化误窖。

使用Class的forName()靜態(tài)方法才會(huì)導(dǎo)致強(qiáng)制初始化該類

類加載器

類加載器負(fù)責(zé)將.class 文件加載到內(nèi)存中叮盘,并為之生成對(duì)應(yīng)的java.lang.Class 對(duì)象

1. 類加載器簡(jiǎn)介

類加載器負(fù)責(zé)加載所有的類,系統(tǒng)為所有被載入內(nèi)存中的類生成一個(gè)java.lang.Class 實(shí)例

當(dāng)JVM啟動(dòng)時(shí)贩猎,會(huì)形成由三個(gè)類加載器組成的初始類加載器層次結(jié)構(gòu)

  • Bootstrap ClassLoader:根類加載器
  • Extension ClassLoader:擴(kuò)展類加載器
  • System ClassLoader:系統(tǒng)類加載器

例子:獲取根類加載器所加載的核心類庫

package com.example;

import java.net.URL;

/**
 * Created by zhoujian on 2017/4/3.
 */

public class Text
{
    public static void main(String[] args)
    {
        //獲取根類加載器所加載的全部URL數(shù)組
        URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
        for (int i = 0; i < urls.length; i++)
        {
            //輸出根類加載器的全部url
            System.out.println(urls[i].toExternalForm());
        }
    }
}

Snip20170404_1.png

Extension ClassLoader:擴(kuò)展類加載器,它負(fù)責(zé)加載JRE的擴(kuò)展目錄(%JAVA_HOME%jre/lib/ext或者由java.ext.dirs系統(tǒng)屬性指定的目錄)中JAR包的類

System ClassLoader:系統(tǒng)類加載器熊户,可以通過ClassLoader的靜態(tài)方法 getSystemClassLoader()來獲取系統(tǒng)類加載器

2. 類加載機(jī)制

JVM的類加載機(jī)制主要要三種:

  • 全盤負(fù)責(zé) :就是當(dāng)一個(gè)類加載器負(fù)責(zé)加載某個(gè)Class時(shí)萍膛,該Class所依賴的和引用的其它Class也將由該類加載器負(fù)責(zé)載入
  • 父類委托:先讓父類加載器試圖加載該Class吭服,只有在父類加載器無法加載該類時(shí)才嘗試從自己的類路徑中加載該類
  • 緩存機(jī)制:所有加載過得Class都會(huì)被緩存,當(dāng)程序中需要使用某個(gè)Class時(shí)蝗罗,類加載器先從緩存中獲取艇棕,只要緩存中不存在該Class對(duì)象時(shí),系統(tǒng)才會(huì)讀取對(duì)應(yīng)的二進(jìn)制數(shù)據(jù)串塑,并轉(zhuǎn)換成Class對(duì)象沼琉,存入緩存中。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末桩匪,一起剝皮案震驚了整個(gè)濱河市打瘪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌傻昙,老刑警劉巖闺骚,帶你破解...
    沈念sama閱讀 222,681評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異妆档,居然都是意外死亡僻爽,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門贾惦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來胸梆,“玉大人,你說我怎么就攤上這事须板∨鼍担” “怎么了?”我有些...
    開封第一講書人閱讀 169,421評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵习瑰,是天一觀的道長(zhǎng)洋措。 經(jīng)常有香客問我,道長(zhǎng)杰刽,這世上最難降的妖魔是什么菠发? 我笑而不...
    開封第一講書人閱讀 60,114評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮贺嫂,結(jié)果婚禮上滓鸠,老公的妹妹穿的比我還像新娘。我一直安慰自己第喳,他們只是感情好糜俗,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,116評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般悠抹。 火紅的嫁衣襯著肌膚如雪珠月。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,713評(píng)論 1 312
  • 那天楔敌,我揣著相機(jī)與錄音啤挎,去河邊找鬼。 笑死卵凑,一個(gè)胖子當(dāng)著我的面吹牛庆聘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播勺卢,決...
    沈念sama閱讀 41,170評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼伙判,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了黑忱?” 一聲冷哼從身側(cè)響起宴抚,我...
    開封第一講書人閱讀 40,116評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎甫煞,沒想到半個(gè)月后菇曲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,651評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡危虱,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,714評(píng)論 3 342
  • 正文 我和宋清朗相戀三年羊娃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片埃跷。...
    茶點(diǎn)故事閱讀 40,865評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蕊玷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出弥雹,到底是詐尸還是另有隱情垃帅,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布剪勿,位于F島的核電站贸诚,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏厕吉。R本人自食惡果不足惜酱固,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,211評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望头朱。 院中可真熱鬧运悲,春花似錦、人聲如沸项钮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至署隘,卻和暖如春宠能,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背磁餐。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評(píng)論 1 274
  • 我被黑心中介騙來泰國打工违崇, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人崖媚。 一個(gè)月前我還...
    沈念sama閱讀 49,299評(píng)論 3 379
  • 正文 我出身青樓亦歉,卻偏偏與公主長(zhǎng)得像恤浪,于是被迫代替她去往敵國和親畅哑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,870評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容