java中的反射機制

反射概念:

Java反射是Java被視爲動態(或準動態)語言的一個關鍵性質。這個機制允許程序在運行時透過Reflection APIs取得任何一個已知名稱的class的內部信息,包括其modifiers(諸如public, static 等)、superclass(例如Object)、實現之interfaces(例如Cloneable),也包括fields和methods的所有信息,並可於運行時改變fields內容或喚起methods。

Java反射機制容許程序在運行時加載、探知、使用編譯期間完全未知的classes。

換言之,Java可以加載一個運行時才得知名稱的class,獲得其完整結構。

反射是Java中一種強大的工具,能夠使我們很方便的創建靈活的代碼,這些代碼可以再運行時裝配,無需在組件之間進行源代碼鏈接。但是反射使用不當會成本很高!


JAVA反射機制提供了什麼功能

提供瞭如下功能:

  • 在運行時判斷任意一個對象所屬的類
  • 在運行時構造任意一個類的對象
  • 在運行時判段任意一個類所具有的成員變量和方法
  • 在運行時調用任一個對象的方法
  • 在運行時創建新類對象
  • 在使用Java的反射功能時,基本首先都要獲取類的Class對象,再通過Class對象獲取其他的對象。

反射機制的作用:

  • 反編譯:.class–>.java
  • 通過反射機制訪問java對象的屬性,方法,構造方法等;

Java中JDK提供的Reflection API

Java反射相關的API在包java.lang.reflect中。

Member接口 該接口可以獲取有關類成員(域或者方法)後者構造函數的信息。

AccessibleObject類 該類是域(field)對象、方法(method)對象、構造函數(constructor)對象的基礎類。它提供了將反射的對象標記爲在使用時取消默認

Java 語言訪問控制檢查的能力。 Array類 該類提供動態地生成和訪問JAVA數組的方法。

Constructor類 提供一個類的構造函數的信息以及訪問類的構造函數的接口。 Field類 提供一個類的域的信息以及訪問類的域的接口。

Method類 提供一個類的方法的信息以及訪問類的方法的接口。

Modifier類 提供了 static方法和常量,對類和成員訪問修飾符進行解碼。

Proxy類 提供動態地生成代理類和類實例的靜態方法。


動態創建代理類

代理模式:代理模式的作用=爲其他對象提供一種代理以控制對這個對象的訪問。

代理模式的角色:

  • 抽象角色:聲明真實對象和代理對象的共同接口
  • 代理角色:代理角色內部包含有真實對象的引用,從而可以操作真實對象。
  • 真實角色:代理角色所代表的真實對象,是我們最終要引用的對象。

動態代理:

  • java.lang.reflect.Proxy
    Proxy 提供用於創建動態代理類和實例的靜態方法,它還是由這些方法創建的所有動態代理類的超類
  • InvocationHandler
    是代理實例的調用處理程序 實現的接口,每個代理實例都具有一個關聯的調用處理程序。對代理實例調用方法時,將對方法調用進行編碼並將其指派到它的調用處理程序的 invoke 方法。

動態Proxy是這樣的一種類:

它是在運行生成的類,在生成時你必須提供一組Interface給它,然後該class就宣稱它實現了這些interface。你可以把該class的實例當作這些interface中的任何一個來用。當然,這個Dynamic Proxy其實就是一個Proxy,它不會替你作實質性的工作,在生成它的實例時你必須提供一個handler,由它接管實際的工作。
在使用動態代理類時,我們必須實現InvocationHandler接口


實例練習:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

public class InvokeTest {
    /**
     * 利用反射機制實現調用方法
     * @param obj
     * @param methodName
     * @throws NoSuchMethodException
     * @throws SecurityException
     * @throws IllegalAccessException
     * @throws IllegalArgumentException
     * @throws InvocationTargetException
     */
    public static void test(String methodName) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        InvokeTest test=new InvokeTest();
        //對象類型
        Class<?> cls=test.getClass();
        //利用反射機制獲取該類型下的方法
        Method method=cls.getMethod(methodName, int.class,String.class);
        //執行該方法
        method.invoke(test, 10,"20");
//      test.method(10,20)
    }
    /**
     * ...代表:一組相同類型的數據(不約束個數)
     * 一個方法裏最多只能有一個...類型
     * ...類型必須出現在參數列表的最後位置
     * @param a
     */
    public static void e(int... a) {
        for(int i=0;i<a.length;i++) {
            System.out.println(a[i]);
        }
    }

    //反射機制
    //調用方法
    //不知道方法名或屬性名
    //通過傳遞參數來實現調用
    public static void main(String[] args) {
        //...省略參數類型
        e(1,2,3,4,5);

        //反射機制
        try {
            test("d");
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            //沒有該方法
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void a() {
        System.out.println("aaaaaaaaaa");
    }

    public void b(int b) {
        System.out.println("b="+b);
    }

    public void c(int a,int b) {
        System.out.println("sum="+(a+b));
    }

    public void d(int a,String b) {
        System.out.println(a+b);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82

具體功能的實現

反射機制獲取類有三種方法,我們來獲取Employee類型。

//第一種方式:  
Classc1 = Class.forName("Employee");  
//第二種方式:  
//java中每個類型都有class 屬性.  
Classc2 = Employee.class;  

//第三種方式:  
//java語言中任何一個java對象都有getClass 方法  
Employeee = new Employee();  
Classc3 = e.getClass(); //c3是運行時類 (e的運行時類是Employee)  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

創建對象:獲取類以後我們來創建它的對象,利用newInstance:

Class c =Class.forName("Employee");  

//創建此Class 對象所表示的類的一個新實例  
Objecto = c.newInstance(); //調用了Employee的無參數構造方法.  
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

獲取屬性:分爲所有的屬性和指定的屬性:
a,先看獲取所有的屬性的寫法:

//獲取整個類  
            Class c = Class.forName("java.lang.Integer");  
              //獲取所有的屬性?  
            Field[] fs = c.getDeclaredFields();  

                   //定義可變長的字符串,用來存儲屬性  
            StringBuffer sb = new StringBuffer();  
            //通過追加的方法,將每個屬性拼接到此字符串中  
            //最外邊的public定義  
            sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() +"{\n");  
            //裏邊的每一個屬性  
            for(Field field:fs){  
                sb.append("\t");//空格  
                sb.append(Modifier.toString(field.getModifiers())+" ");//獲得屬性的修飾符,例如public,static等等  
                sb.append(field.getType().getSimpleName() + " ");//屬性的類型的名字  
                sb.append(field.getName()+";\n");//屬性的名字+回車  
            }  

            sb.append("}");  

            System.out.println(sb);  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

b,獲取特定的屬性,對比着傳統的方法來學習:

public static void main(String[] args) throws Exception{  

<span style="white-space:pre">  </span>//以前的方式:  
    /* 
    User u = new User(); 
    u.age = 12; //set 
    System.out.println(u.age); //get 
    */  

    //獲取類  
    Class c = Class.forName("User");  
    //獲取id屬性  
    Field idF = c.getDeclaredField("id");  
    //實例化這個類賦給o  
    Object o = c.newInstance();  
    //打破封裝  
    idF.setAccessible(true); //使用反射機制可以打破封裝性,導致了java對象的屬性不安全。  
    //給o對象的id屬性賦值"110"  
    idF.set(o, "110"); //set  
    //get  
    System.out.println(idF.get(o));  
}  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

參考博客:

博客1:

http://blog.csdn.net/liujiahan629629/article/details/18013523

博客2:

http://blog.csdn.net/yongjian1092/article/details/7364451

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