jvm原理(11)類加載器重要方法詳解

上一節 我們寫了一個類加載器的實現,其中一個重要的方法是findClass,看一下它的介紹:
https://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html#loadClass(java.lang.String,%20boolean)
findClass:

/**
     * Finds the class with the specified <a href="#name">binary name</a>.
     * This method should be overridden by class loader implementations that
     * follow the delegation model for loading classes, and will be invoked by
     * the {@link #loadClass <tt>loadClass</tt>} method after checking the
     * parent class loader for the requested class.  The default implementation
     * throws a <tt>ClassNotFoundException</tt>.
     *返回了指定二進制名字的class,這個方法應該被遵循父類委託機制的子類去重寫,當檢查完當前類的父類加載器之後,
     * 然後會被loadClass 調動,這個方法默認拋出ClassNotFoundException異常
     * @param  name The <a href="#name">binary name</a> of the class
     * @return  The resulting <tt>Class</tt> object
     * @throws  ClassNotFoundExceptionIf the class could not be found
     * @since  1.2
     */
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        throw new ClassNotFoundException(name);
    }

在findClass方法裏邊,先去加載類的字節碼,然後給ClassLoader類的defineClass方法,將字節碼轉換爲一個Class類型(爲了調用newInstance()實例化),
看一下defineClass的介紹:

defineClass

Converts an array of bytes into an instance of class Class. Before the Class can be used it must be resolved.
This method assigns a default ProtectionDomain to the newly defined class. The ProtectionDomain is effectively granted the same set of permissions returned when Policy.getPolicy().getPermissions(new CodeSource(null, null)) is invoked. The default domain is created on the first invocation of defineClass, and re-used on subsequent invocations.
將一個字節數組轉換爲一個Class類的實例,在這之前需要對Class進行過解析(類的加載過程[加載:連接[驗證,準備,解析]],初始化).
這個方法會給新建立的Class分配一個保護域,保護域是用來保證返回的新的Class的訪問信息是正確的(比如相同包下邊的包的包名是一樣的),默認的域在第一創建的時候會被創建,之後再去調用會被複用。
To assign a specific ProtectionDomain to the class, use the defineClass method that takes a ProtectionDomain as one of its arguments.
如果想要手動指定保護域,需要調用另外一個重載的方法,有5個參數,最後一個參數指定要傳入的保護域。

protected final Class<?> defineClass(String name,byte[] b,int off,int len) throws ClassFormatError;

Parameters:
name - The expected binary name of the class, or null if not known
指定了二進制名字的類,如果不確定就填入null
b - The bytes that make up the class data. The bytes in positions off through off+len-1 should have the format of a valid class file as defined by The Java™ Virtual Machine Specification.
字節數組存儲的是符合Java虛擬機對class文件規範的class文件字節碼,否則是解析不出來的。
off - The start offset in b of the class data
類數據的起始偏移量
len - The length of the class data
class字節碼與類數據相關的長度

Returns:
The Class object that was created from the specified class data.
返回指定了class字節數組的Class的對象。

Throws:
ClassFormatError - If the data did not contain a valid class
如果字節碼數據不是合法的符合虛擬機規範的直接拋出錯誤
IndexOutOfBoundsException - If either off or len is negative, or if off+len is greater than b.length.
偏移量不合法或者計算後不合法拋出IndexOutOfBoundsException
SecurityException - If an attempt is made to add this class to a package that contains classes that were signed by a different set of
certificates than this class (which is unsigned), or if name begins with “java.”.
jdk不允許我們定義以”java.”開頭的包名的類,這樣會拋出安全異常

defineClass方法一直往下跟,會跟到如下的真正實現的方法,是一個native方法:
private native Class

protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException

loadClass方法
Loads the class with the specified binary name. The default implementation of this method searches for classes in the following order:
加載指定二進制名字的類,這個方法的默認實現是按照如下的規則查找
Invoke findLoadedClass(String) to check if the class has already been loaded.
調用findLoadedClass確定這個類是否已經被加載
Invoke the loadClass method on the parent class loader. If the parent is null the class loader built-in to the virtual machine is used, instead.
調用委託父類的loadClass,如果委託父類是是空的,那麼會使用jvm內建的啓動類加載器代替
Invoke the findClass(String) method to find the class.
調用findClass查找這個類。
If the class was found using the above steps, and the resolve flag is true, this method will then invoke the resolveClass(Class) method on the resulting Class object.
如果使用上述步驟找到了這個類,並且resolve 是true,那麼就會將解析結果作爲resolveClass的參數調用resolveClass方法。
Subclasses of ClassLoader are encouraged to override findClass(String), rather than this method.
子類被鼓勵重寫findClass方法,不推薦重寫當前方法
Unless overridden, this method synchronizes on the result of getClassLoadingLock method during the entire class loading process.
除非被重寫,否則這個方法會被同步,保證類只能被加載一次。
Parameters:
name - The binary name of the class
resolve - If true then resolve the class
Returns:
The resulting Class object
Throws:
ClassNotFoundException - If the class could not be found
“`

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