国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

全面解析Java類加載器

2019-11-15 00:34:37
字體:
來源:轉載
供稿:網友
全面解析java類加載器深入理解和探究Java類加載機制----1.java.lang.ClassLoader類介紹

java.lang.ClassLoader類的基本職責就是根據一個指定的類的名稱,找到或者生成其對應的字節代碼,然后從這些字節代碼中定義出一個Java類,即java.lang.Class類的一個實例。

ClassLoader提供了一系列的方法,比較重要的方法如:

2.JVM中類加載器的樹狀層次結構

Java中的類加載器大致可以分成兩類,一類是系統提供的,另外一類則是由Java應用開發人員編寫的。

引導類加載器(bootstrapclassloader):

它用來加載Java的核心庫(jre/lib/rt.jar),是用原生C++代碼來實現的,并不繼承自java.lang.ClassLoader。

加載擴展類和應用程序類加載器,并指定他們的父類加載器,在java中獲取不到。

擴展類加載器(extensionsclassloader):

它用來加載Java的擴展庫(jre/ext/*.jar)。Java虛擬機的實現會提供一個擴展庫目錄。該類加載器在此目錄里面查找并加載Java類。

應用程序類加載器(applicationclassloader):

它根據Java應用的類路徑(CLASSPATH)來加載Java類。一般來說,Java應用的類都是由它來完成加載的。可以通過ClassLoader.getSystemClassLoader()來獲取它。

自定義類加載器(customclassloader):

除了系統提供的類加載器以外,開發人員可以通過繼承java.lang.ClassLoader類的方式實現自己的類加載器,以滿足一些特殊的需求。

以下測試代碼可以證明此層次結構:

public class testClassLoader {    @Test    public void test(){        //application class loader        System.out.PRintln(ClassLoader.getSystemClassLoader());        //extensions class loader        System.out.println(ClassLoader.getSystemClassLoader().getParent());        //bootstrap class loader        System.out.println(ClassLoader.getSystemClassLoader().getParent().getParent());    }}

輸出為:

可以看出ClassLoader類是由AppClassLoader加載的。他的父親是ExtClassLoader,ExtClassLoader的父親無法獲取是因為它是用C++實現的。

3.雙親委派機制

  某個特定的類加載器在接到加載類的請求時,首先將加載任務委托交給父類加載器,父類加載器又將加載任務向上委托,直到最父類加載器,如果最父類加載器可以完成類加載任務,就成功返回,如果不行就向下傳遞委托任務,由其子類加載器進行加載。

雙親委派機制的好處:

  保證java核心庫的安全性(例如:如果用戶自己寫了一個java.lang.String類就會因為雙親委派機制不能被加載,不會破壞原生的String類的加載)

代理模式

  與雙親委派機制相反,代理模式是先自己嘗試加載,如果無法加載則向上傳遞。tomcat就是代理模式。

4.自定義類加載器
public class MyClassLoader extends ClassLoader{    private String rootPath;        public MyClassLoader(String rootPath){        this.rootPath = rootPath;    }        @Override    protected Class<?> findClass(String name) throws ClassNotFoundException {        //check if the class have been loaded        Class<?> c = findLoadedClass(name);                if(c!=null){            return c;        }        //load the class        byte[] classData = getClassData(name);        if(classData==null){            throw new ClassNotFoundException();        }        else{            c = defineClass(name,classData, 0, classData.length);            return c;        }        }        private byte[] getClassData(String className){        String path = rootPath+"/"+className.replace('.', '/')+".class";                InputStream is = null;        ByteArrayOutputStream bos = null;        try {            is = new FileInputStream(path);            bos = new ByteArrayOutputStream();            byte[] buffer = new byte[1024];            int temp = 0;            while((temp = is.read(buffer))!=-1){                bos.write(buffer,0,temp);            }            return bos.toByteArray();        } catch (Exception e) {            e.printStackTrace();        }finally{            try {                is.close();                bos.close();            } catch (Exception e) {                e.printStackTrace();            }                    }                return null;            }    }

測試自定義的類加載器

創建一個測試類HelloWorld

package testOthers;public class HelloWorld {}

在D盤根目錄創建一個testOthers文件夾,編譯HelloWorld.java,將得到的class文件放到testOthers文件夾下。

利用如下代碼進行測試

public class testMyClassLoader {    @Test    public void test() throws Exception{        MyClassLoader loader = new MyClassLoader("D:");        Class<?> c = loader.loadClass("testOthers.HelloWorld");        System.out.println(c.getClassLoader());    }}

輸出:

說明HelloWorld類是被我們的自定義類加載器MyClassLoader加載的

5.類加載過程詳解

JVM將類加載過程分為三個步驟:裝載(Load),鏈接(Link)和初始化(Initialize)

1)裝載:

  查找并加載類的二進制數據;

2)鏈接:

  驗證:確保被加載類信息符合JVM規范、沒有安全方面的問題。

  準備:為類的靜態變量分配內存,并將其初始化為默認值。

  解析:把虛擬機常量池中的符號引用轉換為直接引用。

3)初始化:

  為類的靜態變量賦予正確的初始值。

ps:解析部分需要說明一下,Java中,虛擬機會為每個加載的類維護一個常量池【不同于字符串常量池,這個常量池只是該類的字面值(例如類名、方法名)和符號引用的有序集合。而字符串常量池,是整個JVM共享的】這些符號(如inta=5;中的a)就是符號引用,而解析過程就是把它轉換成指向堆中的對象地址的相對地址。

類的初始化步驟:

1)如果這個類還沒有被加載和鏈接,那先進行加載和鏈接

2)假如這個類存在直接父類,并且這個類還沒有被初始化(注意:在一個類加載器中,類只能初始化一次),那就初始化直接的父類(不適用于接口)

3)如果類中存在static標識的塊,那就依次執行這些初始化語句。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 卫辉市| 伊川县| 滦南县| 得荣县| 额敏县| 永宁县| 广南县| 潞城市| 大竹县| 乌兰察布市| 吉木萨尔县| 保靖县| 两当县| 固原市| 定安县| 嘉禾县| 安顺市| 即墨市| 宁海县| 湾仔区| 泗水县| 邯郸县| 固镇县| 丘北县| 若羌县| 灌云县| 双桥区| 屯门区| 琼中| 布尔津县| 慈利县| 巫山县| 自贡市| 丰原市| 宣威市| 成武县| 聂拉木县| 炉霍县| 外汇| 桓仁| 宝兴县|