這段程序打印出系統類加載器到最上層的加載器的結構關係:
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();