全面解析Java類載入器

來源:互聯網
上載者:User

標籤:

深入理解和探究Java類載入機制----1.java.lang.ClassLoader類介紹

java.lang.ClassLoader類的基本職責就是根據一個指定的類的名稱,找到或者產生其對應的位元組代碼,然後從這些位元組代碼中定義出一個Java 類,即 java.lang.Class類的一個執行個體。

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

 

  2.JVM中類載入器的樹狀階層

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

引導類載入器(bootstrap class loader):

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

載入擴充類和應用程式類載入器,並指定他們的父類載入器,在java中擷取不到。 

擴充類載入器(extensions class loader):

它用來載入 Java 的擴充庫(jre/ext/*.jar)。Java 虛擬機器的實現會提供一個擴充庫目錄。該類載入器在此目錄裡面尋找並載入 Java 類。 

應用程式類載入器(application class loader):

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

自訂類載入器(custom class loader):

除了系統提供的類載入器以外,開發人員可以通過繼承 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共用的】這些符號(如int a = 5;中的a)就是符號引用,而解析過程就是把它轉換成指向堆中的對象地址的相對位址。

 

類的初始化步驟:

1)如果這個類還沒有被載入和連結,那先進行載入和連結

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

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

 

 

 

全面解析Java類載入器

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.