java 反射 類裝載器,java反射類裝載
前言:
java語言允許通過程式化的方式間接對Class進行操作,Class檔案由類裝載器裝載後,在jvm中將形成一份描述Class結構的元資訊對象,通過該元資訊對象可以獲知Class的結構資訊,如建構函式,屬性和方法等,
java允許使用者藉由這個與Class相關的元資訊對象間接調用Class對象的功能,這就為使用程式化方式操作Class對象開闢了途徑。
執行個體:
下面一個Car類擁有兩個建構函式,一個方法及三個屬性
package reflect;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 say(){ System.out.println("brand:"+ brand + ", color:"+ color +", maxSpeed:"+ maxSpeed); }//set和get 方法省略
一般情況下,我們會使用如下代碼建立Car的執行個體:
Car car = new Car();car.setBrand("紅旗");
這種是採用傳統方式直接調用目標類,下面我們可以使用java反射機制以一種間接的方式操控目標類:
public class ReflectTest { public static Car initByDefaultConst() throws Throwable{ // 1. 通過類裝載器擷取Car類的對象 ClassLoader loader = Thread.currentThread().getContextClassLoader(); //使用全限定名來找class類 Class clazz = loader.loadClass("reflect.Car"); /*Class clazz = Class.forName("reflect.Car");*/ //另一種方式擷取class // 2. 擷取類的預設構造器對象並通過它執行個體化Car Constructor cons = clazz.getDeclaredConstructor((Class[])null); Car car = (Car)cons.newInstance(); // 3. 通過反射方法設定屬性 Method setBrand = clazz.getMethod("setBrand", String.class); setBrand.invoke(car,"紅旗"); Method setColor = clazz.getMethod("setColor", String.class); setColor.invoke(car,"黑色"); Method setMaxSpeed = clazz.getMethod("setMaxSpeed", int.class); setMaxSpeed.invoke(car,200); return car; } @Test public void test() throws Throwable{ Car car = initByDefaultConst(); car.say(); }}
運行以上程式,在控制台列印如下: brand:紅旗, color:黑色, maxSpeed:200
上述的程式只是用了很少的api,java反射包為我們提供了很多的方法,可以細查。
其餘擴充:
類裝載器ClassLoader的工作機制:
類裝載器就是尋找類的節碼檔案並構造出類在jvm內部表示對象的組件,在java中,類裝載器把一個類裝入jvm中,需要經過如下步驟:
1. 裝載:尋找和匯入Class檔案
2. 連結:執行校正,準備和解析步驟,其中解析步驟是可以選擇的
2.1. 校正:檢查載入Class檔案資料的正確性
2.2. 準備: 給類的靜態變數分配儲存空間
2.3. 解析:將符號引用轉換成直接引用
3. 初始化:對類的靜態變數,靜態代碼塊執行初始化工作
JVM裝載類使用 “全盤負責委託機制”,
“全盤負責”是指當一個ClassLoader裝載一個類時(除非顯式的使用另一個ClassLoader),該類所依賴及引用的類也由這個ClassLoader載入;
“委託機制”是指先委託父裝載器尋找目標類,只有在找不到的情況下才從自己的類路徑中尋找並裝載目標類。
這一點是從安全形度考慮的,試想,如果有一個人編寫了一個惡意的基礎類(如java.lang.String)並裝載到JVM中,將會引起多麼可怕的後果,
但是由於有了“全盤負責委託機制”,java.lang.String永遠是根裝載器來裝載的,這樣就避免了上述安全隱患的發生。