1. 程式人生 > >java反射的用法

java反射的用法

用法 block bsp protected image ide 是把 ima pre

反射(運行時的類信息),在java裏面得到了大量的使用,尤其是在一些框架裏面(註解等等),多多少少都會用到反射,了解java的反射,對我們以後學習框架和寫框架都會起到非常的重要!

Class類與java.lang.reflect類庫一起對反射的概念進行了支持,該類庫包括了FieId、Method以及Constructor類。這些類型的對象是由JVM在運行時創建的,用以表示未知類裏對應的成員。這樣你就可以使用Constructor創建新的對象,用get()和set()方法讀取和修改與FieId對象關聯的字段,用invoke()方法調用與Method對象關聯的方法,另外還可以調用getFieIds()、getMethods()和getConstructors()等很便利的方法,以返回表示字段、方法以及構造器的對象的數組。

首先,我們創建一個類,代碼如下

public class ReflexObject {
    
    private int a;
    protected int b;
    int c;
    public int d;
    
    public ReflexObject(){
        super();
    }

    public ReflexObject(int a, int b, int c, int d) {
        super();
        this.a = a;
        this.b = b;
        this.c = c;
        
this.d = d; } private void setA(int a){ this.a=a; System.out.println("我是公有方法"); } protected void setB(int b){ this.b=b; System.out.println("我是私有方法"); } void setC(int c){ this.c=c; System.out.println("我是包方法"); }
public void setD(int d){ this.d=d; System.out.println("我是受保護方法"); } @Override public String toString() { return "ReflexObject [a=" + a + ", b=" + b + ", c=" + c + ", d=" + d + "]"; } }

1??通過getConstructors()、getMethods()和getFields()方法獲取類裏面的信息,代碼如下

public static void main(String[] args) {
    Constructor<?>[] constructors = ReflexObject.class.getConstructors();//獲取類裏面的構造器方法
    Method[] methods = ReflexObject.class.getMethods();//獲取類裏面的方法
    Field[] fields = ReflexObject.class.getFields();//獲取類裏面的屬性
    for(Constructor<?> c:constructors){
        System.out.println(c.toString());
    }
    System.out.println("-------------------------------");
    for(Method m:methods){
        System.out.println(m.toString());
    }
    System.out.println("-------------------------------");
    for(Field f:fields){
        System.out.println(f.toString());
    }
    System.out.println("-------------------------------");
}

輸出結果

技術分享

可以看到,通過getConstructors()、getMethods()和getFields()方法獲取類裏面的信息只能是公有的,並且可以獲取到父類Object的公有方法。

2??用invoke()方法調用與Method對象關聯的方法,代碼如下

public static void main(String[] args) {
    ReflexObject rObj=new ReflexObject();
    System.out.println(rObj);
    try {
        Method methodA = ReflexObject.class.getDeclaredMethod("setA", int.class);
        Method methodB = ReflexObject.class.getDeclaredMethod("setB", int.class);
        Method methodC = ReflexObject.class.getDeclaredMethod("setC", int.class);
        Method methodD = ReflexObject.class.getDeclaredMethod("setD", int.class);
        methodA.setAccessible(true);
        methodA.invoke(rObj, 3);
        methodB.setAccessible(true);
        methodB.invoke(rObj, 3);
        methodC.setAccessible(true);
        methodC.invoke(rObj, 3);
        methodD.setAccessible(true);
        methodD.invoke(rObj, 3);
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    System.out.println(rObj);
}

因為invoke(obj,args...)是Method方法,並不知道是要那個對象obj執行改方法,必須指定需要修改那個對象obj,傳遞的參數args

輸出結果如下

技術分享

可以看到,的確是把將屬性0都改成了3,執行了方法,甚至是private方法。註意,除了public方法外,其它的都要將setAccessible設置為true,這個大家可以試一下。

3??通過FieId類直接修改屬性值

public static void main(String[] args) {
    ReflexObject rObj=new ReflexObject();
    System.out.println(rObj);
    try {
        Field fieldA = ReflexObject.class.getDeclaredField("a");
        Field fieldB = ReflexObject.class.getDeclaredField("b");
        Field fieldC = ReflexObject.class.getDeclaredField("c");
        Field fieldD = ReflexObject.class.getDeclaredField("d");
        fieldA.setAccessible(true);
        fieldA.set(rObj, 3);
        fieldB.setAccessible(true);
        fieldB.set(rObj, 3);
        fieldC.setAccessible(true);
        fieldC.set(rObj, 3);
        fieldD.setAccessible(true);
        fieldD.set(rObj, 3);
    } catch (NoSuchFieldException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (SecurityException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }catch (IllegalArgumentException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    System.out.println(rObj);
}

輸出結果

技術分享

結論和註意點類似2??

4??通過Constructor反射出一個對象,代碼如下

public static void main(String[] args) {
    try {
        Constructor<ReflexObject> constructor1 = ReflexObject.class.getDeclaredConstructor();//無參數構造器
        Constructor<ReflexObject> constructor2 = ReflexObject.class.getDeclaredConstructor(int.class,int.class,int.class,int.class);//帶參數的構造器
        ReflexObject object1 = constructor1.newInstance();
        ReflexObject object2 = constructor2.newInstance(3,3,3,3);
        System.out.println(object1);
        System.out.println(object2);
    } catch(Exception e) {
        e.printStackTrace();
    }
}

輸出結果如下

技術分享

這裏我並沒有將setAccessible設置為true,因為我的構造方法都是public,大家可以試一下其它的訪問權限。

ok,反射我就寫到這裏,如果寫的有什麽問題,大家可以在下面留言,謝謝!

java反射的用法