使用反射生成並操作對象


一、獲取Class對象的方式

Java中,每個類被加載到內存中,系統就會為該類生成一個對應的Class對象,通過該Class對象就可以訪問到JVM中的這個類,獲得Class對象有三種方式:

1.使用Class類的forName(String clazzName)靜態方法,該方法需要傳入字符串參數,該字符串參數的值是某個類的全限定類名。

2.通過某個類的class屬性獲取,例如Person.class。

3.調用某個對象的getClass()方法。該方法是java.lang.Object類中的一個方法,所以所有的Java對象都可以調用該方法,該方法將會返回該對象所屬類對應的Class對象。

對於第一種和第二種方法,都是直接根據類來取得該類的Class對象,相比之下,第二種方式有以下優勢:

代碼更安全,程序在編譯階段就可以檢查需要訪問的Class對象是否存在。

程序性能更好,因為這種方式無需調用方法。

二、通過反射創建對象的方式

有兩種方式:

1.使用Class對象的newInstance()方法來創建該Class對象對應類的實例,這種方式要求該Class對象的對應類有默認構造器,而執行newInstance()方法時實際上是利用默認構造器來創建該類的實例。

2.先使用Class對象獲取指定的Constructor對象,再調用Constructor對象的newInstance()方法來創建該Class對象對應類的實例。

三、調用方法

當獲得某個類對應的Class對象后,就可以通過該Class對象的getMethods()方法或者getMethod()方法來獲取全部方法或者指定方法。

每個Method對象對應一個方法,獲得Method對象后,程序就可通過該Method來調用它對應的方法,在Method里面包含一個invoke()方法,該方法的簽名如下:

Object invoke(Object obj,Object... args):該方法中的obj是執行該方法的主調,后面的args是執行該方法時傳入該方法的實參。

下面寫一個例子,對象池工廠,簡單模擬一下Spring框架的IoC思想。

obj.txt中:

a=java.util.Date
b=javax.swing.JFrame
b%title=Title

主代碼:

package demo;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class ObjectPoolFactory {
    //定義一個對象池
    private Map<String, Object> objectPool = new HashMap<String, Object>();
    private Properties props = new Properties();
    
    /**
     * 定義一個創建對象的方法
     * @param clazzName
     * @return
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    private Object createObject(String clazzName) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
        //根據字符串獲取對應的class對象
        Class clazz = Class.forName(clazzName);
        //使用clazz對應類的默認構造器創建實例
        return clazz.newInstance();
    }
    
    /**
     * 初始化properties對象
     * @param fileName
     * @throws IOException
     */
    public void init(String fileName) throws IOException{
        FileInputStream fis = new FileInputStream(fileName);
        props.load(fis);
    }
    
    /**
     * 根據指定文件來初始化對象池
     * 它會根據配置文件來創建對象
     * @throws IOException 
     * @throws IllegalAccessException 
     * @throws InstantiationException 
     * @throws ClassNotFoundException 
     */
    public void initPool() throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException{
        
        for (String name : props.stringPropertyNames()) {
            //每取出一對key-value對,就根據value創建一個對象
            //調用createObject()創建對象,並將對象添加到對象池中
            System.out.println(name);
            if(!name.contains("%")){
                objectPool.put(name, createObject(props.getProperty(name)));
            }
        }
    }
    
    /**
     * 該方法根據屬性文件來調用指定對象的setter方法
     * @throws SecurityException 
     * @throws NoSuchMethodException 
     * @throws InvocationTargetException 
     * @throws IllegalArgumentException 
     * @throws IllegalAccessException 
     */
    public void initProperty() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
        for (String name : props.stringPropertyNames()) {
            //key用於控制對象的setter方法設置值
            //%前面是對象名字,后面是setter方法名
            if(name.contains("%")){
                String[] strs = name.split("%");
                Object target = getObject(strs[0]);
                String method = "set" + strs[1].substring(0, 1).toUpperCase() +
                        strs[1].substring(1);
                //獲取對象實現類多對應的Class對象
                Class targetClass = target.getClass();
                //獲取希望調用的setter方法
                Method mtd = targetClass.getMethod(method, String.class);
                //通過Method的invoke方法執行setter方法
                mtd.invoke(target, props.getProperty(name));
            }
        }
    }
    
    /**
     * 獲取對象
     */
    public Object getObject(String name){
        //從objectPool中取出指定name對應的對象
        return objectPool.get(name);
    }
    
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
        ObjectPoolFactory pf = new ObjectPoolFactory();
        pf.init("obj.txt");
        pf.initPool();
        pf.initProperty();
        System.out.println(pf.getObject("a"));
        System.out.println(pf.getObject("b"));
    }
    
    
}

運行結果:

b
a
b%title
Wed Apr 27 21:51:20 CST 2016
javax.swing.JFrame[frame0,0,0,0x0,invalid,hidden,layout=java.awt.BorderLayout,title=Title,resizable,normal,defaultCloseOperation=HIDE_ON_CLOSE,rootPane=javax.swing.JRootPane[,0,0,0x0,invalid,layout=javax.swing.JRootPane$RootLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=16777673,maximumSize=,minimumSize=,preferredSize=],rootPaneCheckingEnabled=true]

窗口的名字也傳進來了,說明調用setter方法成功。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM