Java反射實踐


參考自:http://www.jianshu.com/p/53eb4e16d00e

參考自:


什麼是反射?

反射(Reflection)能夠讓運行於 JVM 中的程序檢測和修改運行時的行爲

Class 類

在程序運行期間,Java運行時系統始終爲所有的對象維護一個被稱爲運行時的類型標識。虛擬機利用運行時信息選擇相應的方法執行。可以通過專門的Java類訪問這些信息,保存這些信息的類被稱爲Class。

將Class類中的forName和newInstance配合使用,可以根據存儲在字符串中的類名創建一個對象

String s = "java.util.Date";
Object m = Class.forName(s).newInstance();

爲什麼需要反射?

通過反射,我們能夠

  • 在運行時檢測對象的類型;
  • 動態構造某個類的對象;
  • 檢測類的屬性和方法;
  • 任意調用對象的方法;
  • 修改構造函數、方法、屬性的可見性。

JUnit

JUnit通過反射來遍歷包含 @Test 註解的方法,並在運行單元測試時調用它們。

Web框架

開發人員可以在配置文件中定義對各種接口和類的實現。通過反射機制,框架能夠快速地動態初始化所需要的類。

Spring框架使用如下的配置文件:

<bean id="someID" class="com.programcreek.Foo">
    <property name="someField" value="someValue" />
</bean>

當Spring容器處理 bean 元素時,會使用Class.forName("com.programcreek.Foo")來初始化這個類,並再次使用反射獲取 property 元素對應的setter方法,爲對象的屬性賦值。

Servlet

<servlet>
    <servlet-name>someServlet</servlet-name>
    <servlet-class>com.programcreek.WhyReflectionServlet</servlet-class>
<servlet>

如何使用反射?

反射的基本方法

本着不重複造輪子的原則,API 詳細參考自 這裏,下面只做簡單介紹。

在java.lang.reflect包中有三個重要的類:

  • Field:描述類的域
  • Method:描述類的方法
  • Constructor:描述類的構造器

對於public域(包括超類成員):

  • getFields
  • getMethods
  • getConstructors

對於其它域(包括私有和受保護的成員,不包括超類成員):

  • gettDeclaredFields
  • gettDeclaredMethods
  • gettDeclaredConstructors

下面介紹 Java 反射的使用,其中 Person 類及測試完整代碼在本文最後。

加載類

    // 加載類的3種方法
    Class clazz = Class.forName("com.yano.reflect.Person");
    Class clazz1 = new Person().getClass();
    Class class2 = Person.class;

獲取類的無參構造函數,並實例化類

    Class clazz = Class.forName("com.yano.reflect.Person");
    Constructor c = clazz.getConstructor(null);
    Person p = (Person) c.newInstance(null);

獲取類的含參私有構造函數,並實例化類

    Class clazz = Class.forName("com.yano.reflect.Person");
    Constructor c = clazz
            .getDeclaredConstructor(new Class[] { String.class });
    // 由於構造函數是 private 的,所以需要屏蔽Java語言的訪問檢查
    c.setAccessible(true);
    Person p = (Person) c
            .newInstance(new Object[] { "I'm a reflect name!" });

獲取並調用類的無參方法

    Class clazz = Class.forName("com.yano.reflect.Person");
    Constructor c = clazz.getConstructor(null);
    Person p = (Person) c.newInstance(null);
    Method method = clazz.getMethod("fun", null);
    method.invoke(p, null);

獲取並調用類的含參方法

    Class clazz = Class.forName("com.yano.reflect.Person");
    Constructor c = clazz.getConstructor(null);
    Person p = (Person) c.newInstance(null);
    Method method = clazz.getMethod("fun", new Class[] { String.class });
    method.invoke(p, new Object[] { "I'm a reflect method!" });

獲取類的字段

    Class clazz = Class.forName("com.yano.reflect.Person");
    Constructor c = clazz
            .getDeclaredConstructor(new Class[] { String.class });
    // 由於構造函數是 private 的,所以需要獲取控制權限
    c.setAccessible(true);
    Person p = (Person) c
            .newInstance(new Object[] { "I'm a reflect name!" });
    Field f = clazz.getField("name");
    Object value = f.get(p);
    Class type = f.getType();
    System.out.println(type);
    if (type.equals(String.class)) {
        System.out.println((String) value);
    }

完整代碼

Person 類

package com.yano.reflect;

public class Person {

    public String name = "default name";
    public int[] array = new int[10];

    public Person() {
        System.out.println(name);
        for (int i = 0; i < array.length; i++) {
            array[i] = i;
        }
    }

    private Person(String name) {
        this.name = name;
        System.out.println(name);
    }

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

    public void fun(String name) {
        System.out.println(name);
    }

}

test 類

package com.yano.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class test {

    /**
     * 反射:加載類的字節碼
     * 
     * @throws SecurityException
     * @throws NoSuchMethodException
     */
    public static void main(String[] args) throws Exception {

        refGetClass();

        // 獲取並調用無參構造函數
        refGetPublicConstructor();

        // 獲取並調用私有的含參構造函數
        refGetPrivateConstructor();

        // 獲取並調用無參方法 fun
        refGetMethodWithNoArg();

        // 獲取並調用有參數方法 fun
        refGetMethodWithArg();

        // 獲取類的字段
        refGetField();
    }

    private static void refGetField() throws Exception {

        Class clazz = Class.forName("com.yano.reflect.Person");
        Constructor c = clazz
                .getDeclaredConstructor(new Class[] { String.class });
        // 由於構造函數是 private 的,所以需要獲取控制權限
        c.setAccessible(true);
        Person p = (Person) c
                .newInstance(new Object[] { "I'm a reflect name!" });

        Field f = clazz.getField("name");
        Object value = f.get(p);
        Class type = f.getType();
        System.out.println(type);

        if (type.equals(String.class)) {
            System.out.println((String) value);
        }
        System.out.println();
    }

    private static void refGetMethodWithArg() throws Exception {

        Class clazz = Class.forName("com.yano.reflect.Person");
        Constructor c = clazz.getConstructor(null);
        Person p = (Person) c.newInstance(null);

        Method method = clazz.getMethod("fun", new Class[] { String.class });
        method.invoke(p, new Object[] { "I'm a reflect method!" });
        System.out.println();
    }

    private static void refGetMethodWithNoArg() throws Exception {

        Class clazz = Class.forName("com.yano.reflect.Person");
        Constructor c = clazz.getConstructor(null);
        Person p = (Person) c.newInstance(null);

        Method method = clazz.getMethod("fun", null);
        method.invoke(p, null);
        System.out.println();
    }

    private static void refGetPrivateConstructor() throws Exception {

        Class clazz = Class.forName("com.yano.reflect.Person");
        Constructor c = clazz
                .getDeclaredConstructor(new Class[] { String.class });

        // 由於構造函數是 private 的,所以需要屏蔽Java語言的訪問檢查
        c.setAccessible(true);

        Person p = (Person) c
                .newInstance(new Object[] { "I'm a reflect name!" });
        System.out.println();
    }

    private static void refGetPublicConstructor() throws Exception {

        Class clazz = Class.forName("com.yano.reflect.Person");
        Constructor c = clazz.getConstructor(null);

        Person p = (Person) c.newInstance(null);
        System.out.println();
    }

    private static void refGetClass() throws ClassNotFoundException {
        // 加載類的3種方法
        Class clazz = Class.forName("com.yano.reflect.Person");
        Class clazz1 = new Person().getClass();
        Class class2 = Person.class;
        System.out.println();
    }

}


文/被稱爲L的男人(簡書作者)
原文鏈接:http://www.jianshu.com/p/53eb4e16d00e
著作權歸作者所有,轉載請聯繫作者獲得授權,並標註“簡書作者”。

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