java之反射機制

java語言運行通過程序化的方式間接對Class的對象實例操作,Class文件由類裝載器裝在後,在JVM中將形成一份描述Class結構的元信息對象,通過該元信息對象可以獲知Class的結構信息:如構造函數、屬性和方法等。Java允許用戶藉由這個Class相關的元信息對象間接調用Class對象的功能,這就爲使用程序化方式操作Class兌現開闢了途徑。

每一個類在JVM中都擁有一個對應的java.lang.class對象,它提供了類結構信息的描述。Class沒有Public構造方法。Class對象是在裝載類時由JVM通過調用類裝載器中的defineClass()方法自動構造的。

Class只有一個私有的構造方法,只有java虛擬機能夠創建Class對象。

 /*
     * Constructor. Only the Java Virtual Machine creates Class
     * objects.
     */
    private Class() {}

1 簡單例子

public class Car {

	private String brand;
	private String color;
	private int maxSpeed;
	
	public Car(){}
	
	public Car(String brand,String color,int maxSpeed){
		this.brand = brand;
		this.color = color;
		this.maxSpeed = maxSpeed;
	}
	
	public void introduce(){
		System.out.println("brand: "+brand+" ;  color: "+color+" ;  maxspeed: "+maxSpeed);
	}

	public String getBrand() {
		return brand;
	}

	public void setBrand(String brand) {
		this.brand = brand;
	}

	public String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}

	public int getMaxSpeed() {
		return maxSpeed;
	}

	public void setMaxSpeed(int maxSpeed) {
		this.maxSpeed = maxSpeed;
	}
	
	
}

這個是一個普通的pojo類。我們用反射機制構建對象,並給對象屬性賦值。
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class ReflectTest {
	public static Car initByDefaultConst() throws Throwable{
		
		ClassLoader loader = Thread.currentThread().getContextClassLoader();
		Class clazz = loader.loadClass("com.baobaotao.reflect.Car");
		
		Constructor cons = clazz.getDeclaredConstructor((Class[])null);
		Car car = (Car)cons.newInstance();
		
		Method setBrand = clazz.getMethod("setBrand", String.class);
		setBrand.invoke(car, "紅旗CA72");
		
		Method setColor = clazz.getMethod("setColor", String.class);
		setColor.invoke(car, "黑色");
		
		Method setMaxSpeed = clazz.getMethod("setMaxSpeed", int.class);
		setMaxSpeed.invoke(car, 200);
		
		return car;
				
	}
	
	public static void main(String[] args) throws Throwable{
		Car car = initByDefaultConst();
		car.introduce();
		System.out.println("current loader: " + car.getClass().getClassLoader());
//		ClassLoader loader = Thread.currentThread().getContextClassLoader();
//		System.out.println("current loader: "+ loader);
//		System.out.println("parent loader: "+ loader.getParent());
//		System.out.println("grandparent loader: "+loader.getParent().getParent());
	}
}
輸出結果:brand: 紅旗CA72 ;  color: 黑色 ;  maxspeed: 200
current loader: sun.misc.Launcher$AppClassLoader@1372a1a

2  類裝載器ClassLoader

2.1 ClassLoader工作機制

類裝載器就是尋找類的字節碼文件並構造出類在JVM內部表示的對象組件。Java中,ClassLoader把一個類裝入虛擬機,需要下面的步驟:
1. 裝載:查找和導入Class文件:
2. 鏈接:執行校驗、準備和解析步驟,其中解析步驟是可以選擇的;
     a)檢驗:檢查載入的Class文件數據的正確性;
     b)準備:給類的靜態變量分配存儲空間;
     c)解析:將符號引用轉成直接引用;
3.初始化:對類的靜態變量、靜態代碼塊執行初始化操作。

類的裝載工作由ClassLoader及其子類負責的,ClassLoader負責在運行時查找和裝入Class字節碼文件。JVM運行時共產生三個裝載器:根裝載器、ExtClassLoader(擴展類裝載器)和AppClassLoader(系統類裝載器)。其中,根裝載器不是ClassLoader的子類,它是用C++編寫的,我們在java中看不到它。根裝載器負責裝載核心類庫。ExtClassLoader和AppClassLoader都是ClassLoader的子類,其中ExtClassLoader負責加載JRE擴展目錄Ext中的JAR類包;AppClassLoader負責裝載ClassPath路徑下的類包。
JVM裝載類的時候使用”全盤負責委託機制“,”全盤負責“是指當一個ClassLoader裝載一個類的時候,除非顯示地使用另一個ClassLoader,該類所依賴及引用也有這個ClassLoader載入;”委託機制“是指先委託父裝載器尋找目標類,只有在找不到的情況下,才從自己的類路徑中查找並裝載目標類。這樣做就比較安全了,如果有人編寫了一個惡意的基礎類(java.lang.String)並裝載到JVM,會產生非常可怕的後果的。但,使用了 ”全盤負責委託機制“ 後,這個隱患就不存在了。


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