java反射機制

反射是java語言的一個特性,它允程序在運行時(注意不是編譯的時候)來進行自我檢查並且對內部的成員進行操作。例如它允許一個java的類獲取他所有的成員變量和方法並且顯示出來。這個能特定我們不常看到,但是在其他的比如C或者C++語言中很不就存在這個特性。一個常見的例子是在JavaBean中,一些組件可以通過一個構造器來操作。這個構造器就是用的反射在動態加載的時候來獲取的java中類的屬性的。

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


Java反射機制主要提供了以下功能:
在運行時判斷任意一個對象所屬的類;
在運行時構造任意一個類的對象;
在運行時判斷任意一個類所具有的成員變量和方法;
在運行時調用任意一個對象的方法;生成動態代理。

簡單實例

package com.baobaotao.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 introduce() {  
       System.out.println("brand:"+brand+";color:"+color+";maxSpeed:" +maxSpeed); 
    } 
     //省略參數的getter/Setter方法 
     … 
}

一般情況下,我們會使用如下的代碼創建Car的實例:

Car car = new Car(); 
car.setBrand("紅旗CA72");
Car car = new Car("紅旗CA72","黑色");

以上兩種方法都採用傳統方式的直接調用目標類的方法,下面我們通過Java反射機制以一種更加通用的方式間接地操作目標類:

package com.baobaotao. reflect; 
import java.lang.reflect.Constructor; 
import java.lang.reflect.Field; 
import java.lang.reflect.Method; 
public class ReflectTest { 
    public static Car  initByDefaultConst() throws Throwable 
    { 
        //①通過類裝載器獲取Car類對象 
        ClassLoader loader = Thread.currentThread().getContextClassLoader();  
        Class clazz = loader.loadClass("com.baobaotao.reflect.Car");  

          //②獲取類的默認構造器對象並通過它實例化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(); 
    } 
}

輸出結果:
brand:紅旗CA72;color:黑色;maxSpeed:200

這說明我們完全可以通過編程方式調用Class的各項功能,這和直接通過構造函數和方法調用類功能的效果是一致的,只不過前者是間接調用,後者是直接調用罷了。

在ReflectTest中,使用了幾個重要的反射類,分別是ClassLoader、Class、Constructor和Method,通過這些反射類就可以間接調用目標Class的各項功能了。在①處,我們獲取當前線程的ClassLoader,然後通過指定的全限定類“com.baobaotao.beans.Car”裝載Car類對應的反射實例。在②處,我們通過Car的反射類對象獲取Car的構造函數對象cons,通過構造函數對象的newInstrance()方法實例化Car對象,其效果等同於new Car()。在③處,我們又通過Car的反射類對象的getMethod(String methodName,Class paramClass)獲取屬性的Setter方法對象,第一個參數是目標Class的方法名;第二個參數是方法入參的對象類型。獲取方法反射對象後,即可通過invoke(Object obj,Object param)方法調用目標類的方法,該方法的第一個參數是操作的目標類對象實例;第二個參數是目標方法的入參。

粗體所示部分的信息即是通過反射方法操控目標類的元信息,如果我們將這些信息以一個配置文件的方式提供,就可以使用Java語言的反射功能編寫一段通用的代碼對類似於Car的類進行實例化及功能調用操作了。

IOC(Inverse of
Control)可翻譯爲“控制反轉”,但大多數人都習慣將它稱爲“依賴注入”。在Spring中,通過IOC可以將實現類、參數信息等配置在其對應的配置文件中,那麼當需要更改實現類或參數信息時,只需要修改配置文件即可,這種方法在上例的基礎上更進一步的降低了類與類之間的耦合。我們還可以對某對象所需要的其它對象進行注入,這種注入都是在配置文件中做的,Spring的IOC的實現原理利用的就是Java的反射機制

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