Java 反射總結和使用

什麼是反射

官方有段介紹是這麼說的

Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine.

什麼意思呢,就是說反射通常用於需要能夠檢查或修改Java虛擬機中運行的應用程序的運行時行爲的程序。

不是很好懂,我們說下反射能做什麼吧。

  1. 反射可以在運行時動態生成某個類的實例。
  2. 反射可以在運行時獲取某個類的任何的變量並修改變量的值。
  3. 反射可以在運行時執行某個類的任何方法。

如何使用反射

我們針對上面的情況一一說一下如何使用。

我們先定義一個 com.reflect.Demo.java 用來做我們後續的實驗。

package com.reflect;
public class Demo {

    public String pubStr = "public_string";
    private String priStr = "private_string";

    private String getPriStr(String testParam) {
        pubStr = testParam;
        return priStr;
    }

    private String getPriStr() {
        return priStr;
    }

    public Demo() {

    }

    private Demo( String priStr ) {
        this.priStr = priStr;
    }

    @Override
    public String toString() {
        return "Demo{" +
                "pubStr='" + pubStr + '\'' +
                ", priStr='" + priStr + '\'' +
                '}';
    }
}

在運行時動態生成某個類的實例

// 反射第一步是獲取類的 class , 一般有 3 種寫法
Class demoClass = Class.forName("com.reflect.Demo");
// demoClass = Demo.class;
// demoClass = new Demo().getClass();

// 獲取無參構造函數
Constructor constructor = demoClass.getDeclaredConstructor();
// 設置可以訪問
constructor.setAccessible(true);
// 根據構造方法創建實例
Object demo = constructor.newInstance();

// 獲取有參構造函數
Constructor constructor1 = demoClass.getDeclaredConstructor(String.class);
// 設置可以訪問
constructor1.setAccessible(true);
// 根據構造方法創建實例
Object demo1 = constructor1.newInstance("I am String");

下面介紹一種通用的獲取某個類的實例的方法

    /**
     * 運用反射,通過默認的構造方法獲取某個類的實例
     *
     * @param className
     * @return
     */
    public static Object getObjectInstance(String className, Object... args) {
        try {
            Class[] classes = new Class[args.length];
            for (int i = 0; i < args.length; i++) {
                classes[i] = args[i].getClass();
            }
            Class objClass = Class.forName(className);
            Constructor constructor = objClass.getDeclaredConstructor(classes);
            constructor.setAccessible(true);
            return constructor.newInstance(args);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return new Object();
    }

在運行時獲取某個類的任何的變量並修改變量的值

下面的代碼會告訴大家如何獲取 Demo.java 的一個實例的變量 (priStr) 並對其賦值。

// 無參構造方法 new 的實例,裏面的 priStr 值爲 private_string
Demo demo = new Demo();
// 獲取 demo 的 class
Class demoClass = demo.getClass();
// 獲取 priStr 的 Field 
Field priStrField = demoClass.getDeclaredField("priStr");
// 設置可以訪問
priStrField.setAccessible(true);

// 取 priStr 的值
// 要取的是 demo 這個實例的 priStr , 所以需要傳入 demo
Object priStrValue = priStrField.get(demo); 

// 修改 priStr 的值
// 要修改的是 demo 這個實例, 所以需要傳入 demo
priStrField.set(demo,"I am Private String"); 

下面介紹一種通用的獲取屬性的方法

    /**
     * 獲取某個變量的值
     *
     * @param obj       待取值的類
     * @param fieldName 待取值的變量的變量名
     * @return
     */
    public static Object getFieldValue(Object obj, String fieldName) {
        try {
            Field field = obj.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            return field.get(obj);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return new Object();
    }

    /**
     * 設置某個類的某個變量的值
     *
     * @param obj
     * @param fieldName
     * @param fieldValue
     * @return
     */
    public static boolean setFieldValue(Object obj, String fieldName, Object fieldValue) {
        try {
            Field field = obj.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(obj, fieldValue);
            return true;
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return false;
    }

在運行時執行某個類的任何方法

下面的代碼會告訴大家如何獲取 Demo.java 的一個方法(getPriStr) 並調用此方法。

// 無參構造方法 new 的實例,裏面的 priStr 值爲 private_string
Demo demo = new Demo();
// 獲取 demo 的 class
Class demoClass = demo.getClass();

// 獲取無參 getPriStr 對應的 Method 
Method priStrMethod = demoClass.getDeclaredMethod("priStr");
// 設置可以訪問
priStrMethod.setAccessible(true);
// 調用此方法
Object priStr = priStrMethod.invoke(obj);

// 獲取有參 getPriStr 對應的 Method 
Method priStrMethod1 = demoClass.getDeclaredMethod("priStr",String.class);
// 設置可以訪問
priStrMethod1.setAccessible(true);
// 調用此方法
Object priStr1 = priStrMethod1.invoke(obj,"I am testParam");

下面介紹一種通用的調用對象的方法

    /**
     * 調用某個方法
     * @param obj
     * @param methodName
     * @param args
     * @return
     */
    public static Object invokMethod(Object obj, String methodName, Object... args) {
        try {
            Class[] classes = new Class[args.length];
            for (int i = 0; i < args.length; i++) {
                classes[i] = args[i].getClass();
            }
            Method method = obj.getClass().getDeclaredMethod(methodName, classes);
            method.setAccessible(true);
            method.invoke(obj,args);
            return method.invoke(obj, args);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return new Object();
    }

更多用法可參考 DEMO

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