java反射Reflection(一)之的類加載器ClassLoader和Class類

反射就是把Java的各種成分映射成相應的Java類。
  
  反射是java語言的一個特性,它允程序在運行時(注意不是編譯的時候)來進行自我檢查並且對內部的成員進行操作。例如它允許一個java的類獲取他所有的成員變量和方法並且顯示出來。Java 的這一能力在實際應用中也許用得不是很多,但是在其它的程序設計語言中根本就不存在這一特性。例如,Pascal、C 或者 C++ 中就沒有辦法在程序中獲得函數定義相關的信息。 

Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts on objects, within security restrictions. The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or the members declared by a given class.

  上面這段是來自oracle官方文檔。我自己的理解反射就是二進制的可執行文件或者java字節碼(java code)能夠在運行時獲知自己的源代碼(Source code)級別的信息。我們知道程序源代碼被編譯成機器指令後,相關的函數定義、字段等信息程序自己是無法看見的,也不知道,或者說已經沒有了。特別是C、C++。對於java來說,Reflection機制就提供了程序自己發現自己源碼級別信息的功能,這些源碼級別的信息包括類、成員變量、成員函數名等。

 那java是如何在運行時也可以知道自己某個類的各種信息的呢?這裏面先必須說下Class類,注意不是class關鍵字。我們知道java裏面一切皆對象,一切皆類。那麼java程序在運行時,首先得加載他需要的各種類的字節碼,也就是我們的classname.class文件,每一個.class文件就和一個Class類對應起來,在jvm在加載這個.class文件的時候就會實例化一個Class類,並且這個Class類的構造方法是私有的。他只能由JVM創建。(這裏其實是一個工廠模式),其他人不可以直接new出這個Class對象。這個Class類就描述了.class裏面定義的類的各種信息,從而可以獲取。

  類的加載又是又誰來完成呢?是類加載器ClassLoader的各種子類。包括BootStrap、ExtClassLoader、AppClassLoader、customClassLoader等。這些不同的ClassLoader負責加載不同級別的類。下圖是是這幾個ClassLoader的委託模型(Delegate Model也是java的一種重要設計模式)


下面是一個測試代碼:

import java.util.Map.Entry;

public class TestJDKClassLoader {

	public static void main(String[] args) {

		TestJDKClassLoader t = new TestJDKClassLoader();
		t.testClassLoaderClientage();
		t.printSystemInfo();
	}
	
	public void testClassLoaderClientage() {
		ClassLoader loader = this.getClass().getClassLoader();
		System.out.println("本類的類加載器: " + loader.getClass().getName());
		System.out.println("SystemClassLoader: "+ ClassLoader.getSystemClassLoader().getClass()
				.getName());//和上面的等價

		if (loader != null) {
			System.out.println("String 類的類加載器: "+String.class.getClassLoader());//Bootstrap
			System.out.println("AppClassLoader的直接加載器: "
					+ loader.getClass().getClassLoader());//Bootstrap
			ClassLoader fatherLoader = loader.getParent();
			System.out.println("本類的爺爺加載器名稱: "
					+ fatherLoader.getClass().getName());
		}
	}
	
	public void printSystemInfo(){
		for (Entry<Object, Object> entry : System.getProperties().entrySet()) { 
            System.out.println(entry.getKey()+"\t"+entry.getValue()); 
		}
	}
}
打印結果如下:

本類的類加載器: sun.misc.Launcher$AppClassLoader
SystemClassLoader: sun.misc.Launcher$AppClassLoader
String 類的類加載器: null
AppClassLoader的直接加載器: null
本類的爺爺加載器名稱: sun.misc.Launcher$ExtClassLoader

(注:這裏的null其實是bootstrap,因爲這個類是本地語言實現的,在JVM裏,所以看不到)
AppClassLoader負責加載當前運行環境下的類,及java.class.path,他在加載類的時候會向上委託,如果上面的已經加載了該類,自己就不在加載。

發佈了39 篇原創文章 · 獲贊 10 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章