一、獲取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方法成功。