jvm原理(8)不同的類加載器與加載與加載動作分析

這段程序打印出系統類加載器到最上層的加載器的結構關係:

public class MyTest13 {
    public static void main(String[] args) {
        ClassLoader classLoader = ClassLoader.getSystemClassLoader();
        System.out.println(classLoader);

        while(null != classLoader){
            classLoader = classLoader.getParent();
            System.out.println(classLoader);
        }

    }
}

運行結果:

sun.misc.Launcher$AppClassLoader@18b4aac2 【系統類加載器】
sun.misc.Launcher$ExtClassLoader@1540e19d  【擴展類加載器】
null                                       【根類加載器】

可以看到最後輸出的是null。
這行代碼: ClassLoader classLoader = ClassLoader.getSystemClassLoader();得到系統類加載器,看一下doc說明:

/**
     * Returns the system class loader for delegation.  This is the default
     * delegation parent for new <tt>ClassLoader</tt> instances, and is
     * typically the class loader used to start the application.
     *返回一個針對委託的系統類加載器,並且他是默認新建類加載器實例的委託雙親(即自定義類加載器的父級,見下圖),它是一個典型的啓動應用的類加載器。
     * <p> This method is first invoked early in the runtime's startup
     * sequence, at which point it creates the system class loader and sets it
     * as the context class loader of the invoking <tt>Thread</tt>.
     *此方法在運行期的早期就會被調用,在這個時間點創建系統類的加載器,並且設定其爲調用線程的上下文的一個類加載器。
     * <p> The default system class loader is an implementation-dependent
     * instance of this class.
     *默認的系統類加載器與這個類實現相關的實例
     * <p> If the system property "<tt>java.system.class.loader</tt>" is defined
     * when this method is first invoked then the value of that property is
     * taken to be the name of a class that will be returned as the system
     * class loader.  The class is loaded using the default system class loader
     * and must define a public constructor that takes a single parameter of
     * type <tt>ClassLoader</tt> which is used as the delegation parent.  An
     * instance is then created using this constructor with the default system
     * class loader as the parameter.  The resulting class loader is defined
     * to be the system class loader.
     * 如果設定了java.system.class.loader那麼這個方法返回的就是java.system.class.loader設定的類加載器。這個類被系統類加載器加載,並且
     * 定義一個公共的構造方法,接受一個ClassLoader參數用作爲委託的雙親,用默認系統類類加載器作爲構造器的參數,就會創造一個實例 ,所得到的就是系統類加載器
     */
     //返回系統類加載器
         @CallerSensitive
    public static ClassLoader getSystemClassLoader() {
        initSystemClassLoader();
        if (scl == null) {
            return null;
        }
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkClassLoaderPermission(scl, Reflection.getCallerClass());
        }
        return scl;
    }

這裏寫圖片描述

getParent方法:

/**
     * Returns the parent class loader for delegation. Some implementations may
     * use <tt>null</tt> to represent the bootstrap class loader. This method
     * will return <tt>null</tt> in such implementations if this class loader's
     * parent is the bootstrap class loader.
     * 返回父加載器用於委託,有些實現返回null用來表示根類加載器,如果一個類的父加載器是根加載器,那麼這個方法將會返回null
     */
      public final ClassLoader getParent() {
        if (parent == null)
            return null;
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            // Check access to the parent class loader
            // If the caller's class loader is same as this class loader,
            // permission check is performed.
            checkClassLoaderPermission(parent, Reflection.getCallerClass());
        }
        return parent;
    }

parent 變量是ClassLoader的成員變量:

    // The parent class loader for delegation
    // Note: VM hardcoded the offset of this field, thus all new fields
    // must be added *after* it.
    用於委託的雙親加載器,JVM將這個變量的偏移量進行了硬編碼,,這樣新的變量就要加載這個變量的後邊
    private final ClassLoader parent;

下一個例子:

public class MyTest14 {
    public static void main(String[] args) throws IOException {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        String resourceName = "com/twodragonlake/jvm/classloader/MyTest13.class";
        /*
        Finds all the resources with the given name. A resource is some data
        (images, audio, text, etc) that can be accessed by class code in a way
        that is independent of the location of the code.
        返回給定名字所有的資源,資源可以是(圖片,音頻,文本,等)可以被class字節碼以一種與字節碼位置無關的方式去訪問,
        classLoader.getResources(resourceName){....}
        */
        Enumeration<URL> urls =  classLoader.getResources(resourceName);
        while(urls.hasMoreElements()){
            System.out.println(urls.nextElement());
        }

        System.out.println("----------------");

        Class<?> clazz = String.class;
        System.out.println(clazz.getClassLoader());//自定義的類有系統類加載器加載
        System.out.println("----------------");
        clazz = MyTest14.class;
        System.out.println(clazz.getClassLoader());  //由根類加載器加載 因爲系統類加載器的加載目錄包含rt目錄

    }
}

打印:

file:/E:/Study/intelIde/jvm_lecture/out/production/classes/com/twodragonlake/jvm/classloader/MyTest13.class
----------------
null
----------------
sun.misc.Launcher$AppClassLoader@18b4aac2

獲取ClassLoader的方式:
獲得當前類的ClassLoader:
class.getClassLoader();
獲取當前線程上下文的ClassLoader:
Thread.currentThread().getContextClassLoader();
獲得系統的ClassLoader:
ClassLoader.getSystemClassLoader()
獲得調用者的ClassLoader:
DriverManager.getCallerClassLoader();

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章