1. 程式人生 > >JAVA反射簡介與使用示例

JAVA反射簡介與使用示例

JAVA中的反射,所說的意思就是我們可以在程式執行期間內,動態獲取某一個Class物件的所有資訊,包括修飾符(modifiers),屬性(fields),方法(methods)等。

舉個例子就好比家裡的防盜門,各種Class物件就是來敲門的各種人,當我們獲取到一個未知其內容的Class物件的時候,就好比有一個沒有預約的人來敲門,此時我們無法感知門外面的人是誰,他有可能是物業,有可能是外賣小哥,也有可能是查水錶的。而反射就好比門眼,我們通過反射來觀察未知其內容的Class物件,就好比通過門眼來觀察門外的未知的人,這時,門外人的所有資訊我們就可以通過門眼知曉了,他可能是穿著黃衣服的美團小哥,也可能是藍衣服的餓了麼小哥,而且高矮胖瘦,顏值如何,盡在我們的掌握。

但是反射也會消耗系統性能、增加程式複雜度,就好比你去把門眼的時候不得不放棄你正在進行的DOTA團戰一樣,所以,需要在合理的情形下使用才是最好的。


我們先建立需要用到的示例Class類:

ReflectTest:

package reflecttest;

public class ReflectTest {

    static{
        System.out.println("ReflectTest is init");
    }

    public String isPublicField = "defaultPublicField";

    protected String isProtectedField = "defaultprotectedField";

    String isDefaultField = "defaultDefaultField";

    private String isPrivateField = "defaultPrivateField";

    ReflectTest() {
        System.out.println("ReflectTest Constructor for no args");
    }

    public ReflectTest(String arg1) {
        System.out.println("ReflectTest Constructor for String arg1");
    }

    private ReflectTest(String arg1, String arg2) {
        System.out.println("ReflectTest Constructor for String arg1 and String arg2");
    }

    public void isReloadMethod(String arg1) {
        System.out.println("isReloadMethod for String arg1");
    }

    private void isReloadMethod(String arg1, String arg2) {
        System.out.println("isReloadMethod for String arg1 and String arg2");
    }

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

    protected void isProtectedMethod() {
        System.out.println("isProtectedMethod");
    }

    void isDefaultMethod() {
        System.out.println("isDefaultMethod");
    }

    private void isPrivateMethod() {
        System.out.println("isPrivateMethod");
    }

    public String getIsPublicField() {
        return isPublicField;
    }

    public void setIsPublicField(String isPublicField) {
        this.isPublicField = isPublicField;
    }

    public String getIsPrivateField() {
        return isPrivateField;
    }

    public void setIsPrivateField(String isPrivateField) {
        this.isPrivateField = isPrivateField;
    }

    public String getIsProtectedField() {
        return isProtectedField;
    }

    public void setIsProtectedField(String isProtectedField) {
        this.isProtectedField = isProtectedField;
    }

    public String getIsDefaultField() {
        return isDefaultField;
    }

    public void setIsDefaultField(String isDefaultField) {
        this.isDefaultField = isDefaultField;
    }
}

1. 進行反射,首先也是必要的,就是獲取Class物件,一共有三種方法:

public static void main(String[] args) {
    /*
     注意:這種通過 類名.class 方式來獲取class物件的方式並不會初始化ReflectTest類
      */
    Class c1 = ReflectTest.class;
    System.out.println("=====================");
    /*
     當我們獲取到了一個Object物件,但是我們無法確定它屬於哪個物件時
     我們可以通過 物件.getClass()的方式來獲取這個物件的Class物件
      */
    Object reflectTest = new ReflectTest();
    Class c2 = reflectTest.getClass();
    System.out.println("=====================");
    try {
        /**
         * 當我們已知某個類的完整類路徑名稱的時候,可以通過Class.forName()方法來獲取Class物件
         * 但是可能會丟擲 ClassNotFoundException 異常
         */
        Class c3 = Class.forName("reflecttest.ReflectTest");
        /*
         * 每個類只會有一個class物件,因此通過以上三種方法得到的 c1、c2、c3 其實是同一個物件
         * 因此互相之間equals為true
         */
        System.out.println(c1.equals(c2));
        System.out.println(c1.equals(c3));
        System.out.println(c2.equals(c3));
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

控制檯列印如下:

2. 獲取到Class物件後,通過Class物件獲取Class內容的常用方法如下:

getName():獲取類的名稱(包名 . 類名)

getFields():獲取類的所有public修飾的屬性

getField(String name):獲取類的符合指定名稱的public修飾的屬性,無法獲取default、protected、private修飾的屬性

getDeclaredFields():獲取類的所有屬性,包含public、protected、default、private修飾的屬性

getDeclaredField(String name):獲取指定名稱的field屬性,包含public、protected、default、private修飾的屬性

getMethods():獲取所有的public修飾的方法

getMethod(String name, Class<T>... parameterTypes):獲取符合指定方法名稱與引數列表的public修飾的方法,第一個引數為方法名稱,其餘後面的引數都依次為引數列表的各個引數型別

getDeclaredMethods():獲取類的所有方法,包含public、protected、default、private修飾的方法

getDeclaredMethod(String name, Class<T>... parameterTypes):獲取符合指定名稱與引數列表的方法,包含public、protected、default、private修飾的方法,第一個引數為方法名稱,其餘後面的引數都依次為引數列表的各個引數型別

getConstructors():獲取類的所有的public修飾的建構函式

getConstructor(Class<T>... parameterTypes):獲取類的符合指定引數列表的public修飾的構造方法

getDeclaredConstructors():獲取類的所有的建構函式,包含public、protected、default、private修飾的建構函式

getDeclaredConstructor(Class<T>... parameterTypes):獲取類的符合指定引數列表的構造方法,包含public、protected、default、private修飾的構造方法

newInstance():通過該類的無參建構函式進行物件例項化


程式碼示例:

getName():

    public static void main(String[] args) {
        Class classObj = ReflectTest.class;
        // getName() 方法獲取類的完整類路徑名稱
        System.out.println(classObj.getName());
    }

執行結果:


getFields():

    public static void main(String[] args) {
        Class classObj = ReflectTest.class;
        // getFields() 方法獲取所有的 public 修飾符修飾的field屬性
        Field[] publicFields = classObj.getFields();
        Arrays.stream(publicFields).forEach(System.out::println);
    }

執行結果:


getField(String name):

    public static void main(String[] args) {
        Class classObj = ReflectTest.class;
        // getField(String name) 方法獲取指定名稱的 public 修飾的field屬性,無法獲取非public修飾的field
        try {
            Field publicField = classObj.getField("isPublicField");
            System.out.println("publicField:"+ publicField);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        try {
            Field protectedField = classObj.getField("isProtectedField");
            System.out.println("protectedField:"+ protectedField);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        try {
            Field defaultField = classObj.getField("isDefaultField");
            System.out.println("defaultField:"+ defaultField);
        } catch (NoSuchFieldException e) {
        e.printStackTrace();
        }
        try {
            Field privateField = classObj.getField("isPrivateField");
            System.out.println("privateField:"+ privateField);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }

執行結果:


getDeclaredFields():

    public static void main(String[] args) {
        Class classObj = ReflectTest.class;
        // getFields() 方法獲取所有的 public 修飾符修飾的field屬性
        Field[] publicFields = classObj.getDeclaredFields();
        Arrays.stream(publicFields).forEach(System.out::println);
    }

執行結果:


getDeclaredFields():

    public static void main(String[] args) {
        Class classObj = ReflectTest.class;
        // getDeclaredField(String name) 方法獲取指定名稱的field屬性,包含public、protected、default、private修飾的屬性
        try {
            Field publicField = classObj.getDeclaredField("isPublicField");
            System.out.println("publicField:" + publicField);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        try {
            Field protectedField = classObj.getDeclaredField("isProtectedField");
            System.out.println("protectedField:" + protectedField);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        try {
            Field defaultField = classObj.getDeclaredField("isDefaultField");
            System.out.println("defaultField:" + defaultField);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        try {
            Field privateField = classObj.getDeclaredField("isPrivateField");
            System.out.println("privateField:" + privateField);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }

執行結果:


getMethods():

    public static void main(String[] args) {
        Class classObj = ReflectTest.class;
        // getMethods()方法會獲取所有的public修飾的方法
        Method[] methods = classObj.getMethods();
        Arrays.stream(methods).forEach(System.out::println);
    }

執行結果:


getMethod(String name, Class<T>... parameterTypes):

    public static void main(String[] args) {
        Class classObj = ReflectTest.class;
        Method method;
        // getMethod(String name, Class<T>... parameterTypes)方法會獲取符合指定名稱與引數列表的public修飾的方法
        try {
            method = classObj.getMethod("isReloadMethod", String.class);
            System.out.println("String.class(public):" + method);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        try {
            method = classObj.getMethod("isReloadMethod", String.class, String.class);
            System.out.println("String.class, String.class(private):" + method);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        try {
            // 因為本身ReflectTest類就不具備引數列表為只接受一個Integer型別的isReloadMethod方法,所以會報出沒有目標方法的異常
            method = classObj.getMethod("isReloadMethod", Integer.class);
            System.out.println("Integer.class(not exits):" + method);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

執行結果:


getDeclaredMethods():

    public static void main(String[] args) {
        Class classObj = ReflectTest.class;
        // getDeclaredMethods()方法會獲取所有的方法
        Method[] methods = classObj.getDeclaredMethods();
        Arrays.stream(methods).forEach(System.out::println);
    }

執行結果:


getDeclaredMethod(String name, Class<T>... parameterTypes):

    public static void main(String[] args) {
        Class classObj = ReflectTest.class;
        Method method;
        // getDeclaredMethod(String name, Class<T>... parameterTypes)方法會獲取符合指定名稱與引數列表的方法
        try {
            method = classObj.getDeclaredMethod("isReloadMethod", String.class);
            System.out.println("String.class(public):"+method);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        try {
            method = classObj.getDeclaredMethod("isReloadMethod", String.class, String.class);
            System.out.println("String.class, String.class(private):"+method);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        try {
            // 因為本身ReflectTest類就不具備引數列表為只接受一個Integer型別的isReloadMethod方法,所以會報出沒有目標方法的異常
            method = classObj.getDeclaredMethod("isReloadMethod", Integer.class);
            System.out.println("Integer.class(not exits):"+method);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

執行結果:


getConstructors():

    public static void main(String[] args) {
        Class classObj = ReflectTest.class;
        Constructor[] constructors = classObj.getConstructors();
        Arrays.stream(constructors).forEach(System.out::println);
    }

執行結果:


getConstructor(Class<T>... parameterTypes):

    public static void main(String[] args) {
        Class classObj = ReflectTest.class;
        Constructor constructor;
        // getConstructor(Class<T>... parameterTypes)方法會獲取符合指定引數列表的public修飾的構造方法
        try {
            constructor = classObj.getConstructor();
            System.out.println("no args(default):" + constructor);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        try {
            constructor = classObj.getConstructor(String.class);
            System.out.println("String.class(public):" + constructor);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        try {
            constructor = classObj.getConstructor(String.class, String.class);
            System.out.println("String.class, String.class(private):" + constructor);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        try {
            // 因為本身ReflectTest類就不具備引數列表為只接受一個Integer型別的建構函式,所以會報出沒有目標方法的異常
            constructor = classObj.getConstructor(Integer.class);
            System.out.println("Integer.class(not exits):" + constructor);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

執行結果:


getDeclaredConstructors():

    public static void main(String[] args) {
        Class classObj = ReflectTest.class;
        Constructor[] constructors = classObj.getDeclaredConstructors();
        Arrays.stream(constructors).forEach(System.out::println);
    }

執行結果:


getDeclaredConstructor(Class<T>... parameterTypes):

    public static void main(String[] args) {
        Class classObj = ReflectTest.class;
        Constructor constructor;
        // getDeclaredConstructor(Class<T>... parameterTypes)方法會獲取符合指定引數列表的構造方法
        try {
            constructor = classObj.getDeclaredConstructor();
            System.out.println("no args(default):" + constructor);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        try {
            constructor = classObj.getDeclaredConstructor(String.class);
            System.out.println("String.class(public):" + constructor);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        try {
            constructor = classObj.getDeclaredConstructor(String.class, String.class);
            System.out.println("String.class, String.class(private):" + constructor);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        try {
            constructor = classObj.getDeclaredConstructor(Integer.class);
            System.out.println("Integer.class(not exits):" + constructor);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

執行結果:


newInstance():

    public static void main(String[] args) {
        Class classObj = ReflectTest.class;
        // newInstance()方法會通過該類的無參建構函式進行物件例項化
        try {
            Object reflectTest = classObj.newInstance();
            System.out.println(reflectTest);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

執行結果: