java中的反射機制淺析

asterisk發表於2015-06-05

Java中,反射是一種強大的工具,它允許執行中的java程式對自身進行檢查,並能直接操作程式的內部屬性。反射允許我們執行的時候使程式碼直接裝載到JVM中類的內部資訊。所以想要構建靈活的應用,反射必不可少。 這裡我將根據物件導向設計的方式來寫一個小demo,根據反射來載入不同的類,使系統具有比較好的擴充套件性。

首先設計一個介面:

package cc.hao.reflect;

import java.util.List;

public interface Action {

    public List<String> act(List<String> params);

}

接下來為不同的功能編寫不同的類,繼承Action介面,針對介面程式設計。

//Store類
package cc.hao.reflect;

import java.util.ArrayList;
import java.util.List;

public class Store implements Action{

    @Override
    public List<String> act(List<String> params) {
        List<String> result = new ArrayList<>();
        result.add("this is store");
        return result;
    }
}
//Load類
package cc.hao.reflect;

import java.util.ArrayList;
import java.util.List;

public class Load implements Action{

    @Override
    public List<String> act(List<String> params) {
        List<String> result = new ArrayList<>();
        result.add("this is load");
        return result;
    }

}

... 我們會需要編寫很多的類,每次具體化哪個類呢?如果向程式傳遞一個引數,然後讓它去自行例項化,執行它的act()方法,那就可以避免以後的麻煩了。

利用反射,一切都迎刃而解。

首先編寫配置檔案:emp.properties

100=Load
200=Search
300=Store

然後我們利用反射來進行動態載入呼叫

package cc.hao.reflect;

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

public class DynamicLoad {

   //這段程式碼用來載入配置檔案,查詢出需要的類名
    Public String loadProp(String head) throws IOException{
        String result = null;
        Properties prop = new Properties();
FileInputStream fis = new FileInputStream("emp.properties");
        prop.load(fis);
        result = prop.getProperty(head);
        fis.close();
        return result;

    }

    //用反射找出需要呼叫的類,發揮了面向介面程式設計的用處
@SuppressWarnings({ "unchecked", "rawtypes" })
    public String loadClass(String head,String content) throws Exception{
        String result = null;
        String s = "cc.hao.reflect." + this.loadProp(head);
        Class className = Class.forName(s);
        Action action = (Action) className.newInstance();
        Class[] params = new Class[1];
        params[0] = Class.forName("java.util.List");
        Method method = className.getMethod("act",params);
        Object[] args = new Object[1];
        List<String> array = new ArrayList<>();
        array.add(content);
        args[0] = array;
        Object returnObject = method.invoke(action, args);
        System.out.println(returnObject);
        return result;
    }


    public static void main(String[] args) throws Exception {
        DynamicLoad reflect = new DynamicLoad();
        reflect.loadClass(args[0], "");
      }
}

測試結果:
Java DynamicLoad 100  | [this is load]
Java DynamicLoad 200  | [this is search]

接下來我們再來看一段程式碼:

package cc.hao.reflection;

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

public class TestReflect {

    public Object copy(Object obj) throws Exception{

        Class<?> clazz = obj.getClass();
        System.out.println("Class:" + clazz.getName());

        Object objCopy = clazz.getConstructor(new Class[]{}).newInstance();
        Field[] fields = clazz.getDeclaredFields();
    }
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            String fieldName = field.getName();
            String firstLetter = fieldName.substring(0,1).toUpperCase();
            String getMethodName = "get" + firstLetter + fieldName.substring(1);
            String setMethodName = "set" + firstLetter + fieldName.substring(1);
            Method getMethod = clazz.getMethod(getMethodName,new Class[]{} );
            Method setMethod = clazz.getMethod(setMethodName, new Class[]{field.getType()});
            Object value = getMethod.invoke(obj, new Object[]{});
            System.out.println(fieldName + ":" + value);
            setMethod.invoke(objCopy, new Object[]{value});

        }

        return objCopy;

    }

    public static void main(String[] args) throws Exception {
        Customer customer = new Customer("liuyu",20);
        customer.setId(30);
        Customer customerCopy = (Customer) new TestReflect().copy(customer);
        System.out.println(customerCopy);
    }

}

class Customer{

    private int id;
    private String name;
    private int age;

    public Customer() {

    }
    public Customer(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Customer [id=" + id + ", name=" + name + ", age=" + age + "]";
    }

}

這裡我們通過反射來複制一個Customer物件。我建議您認真閱讀關於涉及到的API的文件,著重理解

Object objCopy = clazz.getConstructor(new Class[]{}).newInstance();
Method setMethod = clazz.getMethod(setMethodName, new Class[]{field.getType()});

裡的引數含義,這裡就不在多說了。

對於反射一直是很多人不甚理解的地方,參考了一些網上的文章,希望通過一些簡單的例子引導您加深對反射的認識,寫的比較膚淺,不對之處還請您指正。

相關文章