国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

JAVA類加載機(jī)制全解析

tomener / 539人閱讀

摘要:當(dāng)程序使用某個(gè)類時(shí),如果該類還沒被初始化,加載到內(nèi)存中,則系統(tǒng)會通過加載連接初始化三個(gè)過程來對該類進(jìn)行初始化。一旦一個(gè)類被加載到中之后,就不會再次載入了。它既可以從本地文件系統(tǒng)獲取二進(jìn)制文件來加載類,也可以遠(yuǎn)程主機(jī)獲取二進(jìn)制文件來加載類。

當(dāng)程序使用某個(gè)類時(shí),如果該類還沒被初始化,加載到內(nèi)存中,則系統(tǒng)會通過加載、連接、初始化三個(gè)過程來對該類進(jìn)行初始化。該過程就被稱為類的初始化

類加載

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

類文件來源

從本地文件系統(tǒng)加載的class文件

從JAR包加載class文件

從網(wǎng)絡(luò)加載class文件

把一個(gè)Java源文件動(dòng)態(tài)編譯,并執(zhí)行加載

類加載器通常無須等到“首次使用”該類時(shí)才加載該類,JVM允許系統(tǒng)預(yù)先加載某些類

類加載器

類加載器就是負(fù)責(zé)加載所有的類,將其載入內(nèi)存中,生成一個(gè)java.lang.Class實(shí)例。一旦一個(gè)類被加載到JVM中之后,就不會再次載入了。

根類加載器(Bootstrap ClassLoader):其負(fù)責(zé)加載Java的核心類,比如String、System這些類

拓展類加載器(Extension ClassLoader):其負(fù)責(zé)加載JRE的拓展類庫

系統(tǒng)類加載器(System ClassLoader):其負(fù)責(zé)加載CLASSPATH環(huán)境變量所指定的JAR包和類路徑

用戶類加載器:用戶自定義的加載器,以類加載器為父類

類加載器之間的父子關(guān)系并不是繼承關(guān)系,是類加載器實(shí)例之間的關(guān)系

    public static void main(String[] args) throws IOException {
        ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
        System.out.println("系統(tǒng)類加載");
        Enumeration em1 = systemLoader.getResources("");
        while (em1.hasMoreElements()) {
            System.out.println(em1.nextElement());
        }
        ClassLoader extensionLader = systemLoader.getParent();
        System.out.println("拓展類加載器" + extensionLader);
        System.out.println("拓展類加載器的父" + extensionLader.getParent());
    }

結(jié)果

系統(tǒng)類加載
file:/E:/gaode/em/bin/
拓展類加載器sun.misc.Launcher$ExtClassLoader@6d06d69c
拓展類加載器的父null

為什么根類加載器為NULL?

根類加載器并不是Java實(shí)現(xiàn)的,而且由于程序通常須訪問根加載器,因此訪問擴(kuò)展類加載器的父類加載器時(shí)返回NULL

JVM類加載機(jī)制

全盤負(fù)責(zé),當(dāng)一個(gè)類加載器負(fù)責(zé)加載某個(gè)Class時(shí),該Class所依賴的和引用的其他Class也將由該類加載器負(fù)責(zé)載入,除非顯示使用另外一個(gè)類加載器來載入

父類委托,先讓父類加載器試圖加載該類,只有在父類加載器無法加載該類時(shí)才嘗試從自己的類路徑中加載該類

緩存機(jī)制,緩存機(jī)制將會保證所有加載過的Class都會被緩存,當(dāng)程序中需要使用某個(gè)Class時(shí),類加載器先從緩存區(qū)尋找該Class,只有緩存區(qū)不存在,系統(tǒng)才會讀取該類對應(yīng)的二進(jìn)制數(shù)據(jù),并將其轉(zhuǎn)換成Class對象,存入緩存區(qū)。這就是為什么修改了Class后,必須重啟JVM,程序的修改才會生效

URLClassLoader類

URLClassLoader為ClassLoader的一個(gè)實(shí)現(xiàn)類,該類也是系統(tǒng)類加載器和拓展類加載器的父類(繼承關(guān)系)。它既可以從本地文件系統(tǒng)獲取二進(jìn)制文件來加載類,也可以遠(yuǎn)程主機(jī)獲取二進(jìn)制文件來加載類。

兩個(gè)構(gòu)造器

URLClassLoader(URL[] urls):使用默認(rèn)的父類加載器創(chuàng)建一個(gè)ClassLoader對象,該對象將從urls所指定的路徑來查詢并加載類

URLClassLoader(URL[] urls,ClassLoader parent):使用指定的父類加載器創(chuàng)建一個(gè)ClassLoader對象,其他功能與前一個(gè)構(gòu)造器相同

import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import com.mysql.jdbc.Driver;

public class GetMysql {
    private static Connection conn;
    public static Connection getConn(String url,String user,String pass) throws MalformedURLException, InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException{
        if(conn==null){
            URL[]urls={new URL("file:mysql-connector-java-5.1.18.jar")};
            URLClassLoader myClassLoader=new URLClassLoader(urls);
            Driver driver=(Driver) myClassLoader.loadClass("com.mysql.jdbc.Driver").newInstance();
            Properties pros=new Properties();
            pros.setProperty("user", user);
            pros.setProperty("password", pass);
            conn=driver.connect(url, pros);
        }
        return conn;
    }
    public static method1 getConn() throws MalformedURLException, InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException{
        
            URL[]urls={new URL("file:com.em")};
            URLClassLoader myClassLoader=new URLClassLoader(urls);
            method1 driver=(method1) myClassLoader.loadClass("com.em.method1").newInstance();
        
        return driver;
    }
    
    public static void main(String[] args) throws MalformedURLException, InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException {
        System.out.println(getConn("jdbc:mysql://10.10.16.11:3306/auto?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true", "jiji", "jiji"));
        System.out.println(getConn());
    }
}

獲得URLClassLoader對象后,調(diào)用loanClass()方法來加載指定的類

自定義類加載器
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Method;

public class CompileClassLoader extends ClassLoader

{

    // 讀取一個(gè)文件的內(nèi)容

    @SuppressWarnings("resource")
    private byte[] getBytes(String filename) throws IOException

    {

        File file = new File(filename);

        long len = file.length();

        byte[] raw = new byte[(int) len];

        FileInputStream fin = new FileInputStream(file);

        // 一次讀取class文件的全部二進(jìn)制數(shù)據(jù)

        int r = fin.read(raw);

        if (r != len)

            throw new IOException("無法讀取全部文件" + r + "!=" + len);

        fin.close();
        return raw;

    }

    // 定義編譯指定java文件的方法

    private boolean compile(String javaFile) throws IOException

    {

        System.out.println("CompileClassLoader:正在編譯" + javaFile + "……..");

        // 調(diào)用系統(tǒng)的javac命令

        Process p = Runtime.getRuntime().exec("javac" + javaFile);

        try {

            // 其它線程都等待這個(gè)線程完成

            p.waitFor();

        } catch (InterruptedException ie)

        {

            System.out.println(ie);

        }

        // 獲取javac 的線程的退出值

        int ret = p.exitValue();

        // 返回編譯是否成功

        return ret == 0;

    }

    // 重寫Classloader的findCLass方法

    protected Class findClass(String name) throws ClassNotFoundException

    {

        Class clazz = null;

        // 將包路徑中的.替換成斜線/

        String fileStub = name.replace(".", "/");

        String javaFilename = fileStub + ".java";

        String classFilename = fileStub + ".class";

        File javaFile = new File(javaFilename);

        File classFile = new File(classFilename);

        // 當(dāng)指定Java源文件存在,且class文件不存在,或者Java源文件的修改時(shí)間比class文件//修改時(shí)間晚時(shí),重新編譯

        if (javaFile.exists() && (!classFile.exists())
                || javaFile.lastModified() > classFile.lastModified())

        {

            try {

                // 如果編譯失敗,或該Class文件不存在

                if (!compile(javaFilename) || !classFile.exists())

                {

                    throw new ClassNotFoundException("ClassNotFoundException:"
                            + javaFilename);

                }

            } catch (IOException ex)

            {

                ex.printStackTrace();

            }

        }

        // 如果class文件存在,系統(tǒng)負(fù)責(zé)將該文件轉(zhuǎn)化成class對象

        if (classFile.exists())

        {

            try {

                // 將class文件的二進(jìn)制數(shù)據(jù)讀入數(shù)組

                byte[] raw = getBytes(classFilename);

                // 調(diào)用Classloader的defineClass方法將二進(jìn)制數(shù)據(jù)轉(zhuǎn)換成class對象

                clazz = defineClass(name, raw, 0, raw.length);

            } catch (IOException ie)

            {

                ie.printStackTrace();

            }

        }

        // 如果claszz為null,表明加載失敗,則拋出異常

        if (clazz == null) {

            throw new ClassNotFoundException(name);

        }

        return clazz;

    }

    // 定義一個(gè)主方法

    public static void main(String[] args) throws Exception

    {

        // 如果運(yùn)行該程序時(shí)沒有參數(shù),即沒有目標(biāo)類

        if (args.length < 1) {

            System.out.println("缺少運(yùn)行的目標(biāo)類,請按如下格式運(yùn)行java源文件:");

            System.out.println("java CompileClassLoader ClassName");

        }

        // 第一個(gè)參數(shù)是需要運(yùn)行的類

        String progClass = args[0];

        // 剩下的參數(shù)將作為運(yùn)行目標(biāo)類時(shí)的參數(shù),所以將這些參數(shù)復(fù)制到一個(gè)新數(shù)組中

        String progargs[] = new String[args.length - 1];

        System.arraycopy(args, 1, progargs, 0, progargs.length);

        CompileClassLoader cl = new CompileClassLoader();

        // 加載需要運(yùn)行的類

        Class clazz = cl.loadClass(progClass);

        // 獲取需要運(yùn)行的類的主方法

        Method main = clazz.getMethod("main", (new String[0]).getClass());

        Object argsArray[] = { progargs };

        main.invoke(null, argsArray);

    }

}

JVM中除了根類加載器之外的所有類的加載器都是ClassLoader子類的實(shí)例,通過重寫ClassLoader中的方法,實(shí)現(xiàn)自定義的類加載器

loadClass(String name,boolean resolve):為ClassLoader的入口點(diǎn),根據(jù)指定名稱來加載類,系統(tǒng)就是調(diào)用ClassLoader的該方法來獲取制定累對應(yīng)的Class對象

findClass(String name):根據(jù)指定名稱來查找類

推薦使用findClass方法

類的鏈接

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

三個(gè)階段

驗(yàn)證:檢驗(yàn)被加載的類是否有正確的內(nèi)部結(jié)構(gòu),并和其他類協(xié)調(diào)一致

準(zhǔn)備:負(fù)責(zé)為類的類變量分配內(nèi)存。并設(shè)置默認(rèn)初始值

解析:將類的二進(jìn)制數(shù)據(jù)中的符號引用替換成直接引用

類的初始化

JVM負(fù)責(zé)對類進(jìn)行初始化,主要對類變量進(jìn)行初始化

在Java中對類變量進(jìn)行初始值設(shè)定有兩種方式:①聲明類變量是指定初始值②使用靜態(tài)代碼塊為類變量指定初始值

JVM初始化步驟

假如這個(gè)類還沒有被加載和連接,則程序先加載并連接該類

假如該類的直接父類還沒有被初始化,則先初始化其直接父類

假如類中有初始化語句,則系統(tǒng)依次執(zhí)行這些初始化語句

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

創(chuàng)建類實(shí)例。也就是new的方式

調(diào)用某個(gè)類的類方法

訪問某個(gè)類或接口的類變量,或?yàn)樵擃愖兞抠x值

使用反射方式強(qiáng)制創(chuàng)建某個(gè)類或接口對應(yīng)的java.lang.Class對象

初始化某個(gè)類的子類,則其父類也會被初始化

直接使用java.exe命令來運(yùn)行某個(gè)主類

類加載機(jī)制(類加載過程和類加載器)

更多內(nèi)容可以關(guān)注微信公眾號,或者訪問AppZone網(wǎng)站

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/66010.html

相關(guān)文章

  • Java加載機(jī)制

    摘要:如果需要支持類的動(dòng)態(tài)加載或需要對編譯后的字節(jié)碼文件進(jìn)行解密操作等,就需要與類加載器打交道了。雙親委派模型,雙親委派模型,約定類加載器的加載機(jī)制。任何之類的字節(jié)碼都無法調(diào)用方法,因?yàn)樵摲椒ㄖ荒茉陬惣虞d的過程中由調(diào)用。 jvm系列 垃圾回收基礎(chǔ) JVM的編譯策略 GC的三大基礎(chǔ)算法 GC的三大高級算法 GC策略的評價(jià)指標(biāo) JVM信息查看 GC通用日志解讀 jvm的card table數(shù)據(jù)...

    aervon 評論0 收藏0
  • JAVA 虛擬機(jī)加載機(jī)制和字節(jié)碼執(zhí)行引擎

    摘要:實(shí)現(xiàn)這個(gè)口號的就是可以運(yùn)行在不同平臺上的虛擬機(jī)和與平臺無關(guān)的字節(jié)碼。類加載過程加載加載是類加載的第一個(gè)階段,虛擬機(jī)要完成以下三個(gè)過程通過類的全限定名獲取定義此類的二進(jìn)制字節(jié)流。驗(yàn)證目的是確保文件字節(jié)流信息符合虛擬機(jī)的要求。 引言 我們知道java代碼編譯后生成的是字節(jié)碼,那虛擬機(jī)是如何加載這些class字節(jié)碼文件的呢?加載之后又是如何進(jìn)行方法調(diào)用的呢? 一 類文件結(jié)構(gòu) 無關(guān)性基石 ja...

    RichardXG 評論0 收藏0
  • Java加載機(jī)制

    摘要:類加載器類加載器執(zhí)行的操作就是上述加載階段做的事,通過一個(gè)類的全限定名來獲取定義這個(gè)類的二進(jìn)制字節(jié)流,類加載器可以分為下列三種。應(yīng)用程序類加載器,也稱為系統(tǒng)類加載器。 類加載流程: showImg(https://segmentfault.com/img/bV8SRP?w=1152&h=388);從上面這幅圖可以看出一個(gè)類從加載到卸載有7個(gè)階段,其中驗(yàn)證、準(zhǔn)備和解析這三個(gè)步驟統(tǒng)稱為連接...

    missonce 評論0 收藏0
  • 虛擬機(jī)加載機(jī)制

    摘要:加載階段在類的加載階段,虛擬機(jī)需要完成以下件事情通過一個(gè)類的全限定名來獲取定義此類的二進(jìn)制字節(jié)流。驗(yàn)證階段驗(yàn)證是連接階段的第一步,這一階段的目的是為了確保文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機(jī)的要求,并且不會危害虛擬機(jī)自身的安全。 注:本篇文章中的內(nèi)容是根據(jù)《深入理解Java虛擬機(jī)--JVM高級特性與最佳實(shí)踐》而總結(jié)的,如有理解錯(cuò)誤,歡迎大家指正! 虛擬機(jī)把描述類的數(shù)據(jù)從Class文件...

    k00baa 評論0 收藏0
  • java加載機(jī)制

    摘要:在加載階段,虛擬機(jī)要完成件事情通過一個(gè)類的全限定名來獲取定義此類的二進(jìn)制字節(jié)流。前面的階段中,除了加載的時(shí)候,可以由用戶指定自定義類加載器之外,別的都是由虛擬機(jī)主導(dǎo)控制。 java類加載機(jī)制 代碼編譯的結(jié)果從本地機(jī)器碼轉(zhuǎn)變?yōu)樽止?jié)碼,是存儲格式發(fā)展的一小步,確實(shí)編程語言發(fā)展的一大步 虛擬機(jī)把描述類的數(shù)據(jù)從class文件加載到內(nèi)存,并對數(shù)據(jù)進(jìn)行校驗(yàn)、轉(zhuǎn)換解析和初始化,最終形成可以被虛擬機(jī)直...

    garfileo 評論0 收藏0

發(fā)表評論

0條評論

tomener

|高級講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<