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