黑马程序员技术交流社区

标题: 使用反射生成对象 [打印本页]

作者: tomson_tang    时间: 2015-2-2 11:38
标题: 使用反射生成对象
class对象可以获得该类里的方法(由Method对象表示)、构造器(由constructor对象表示)、Filed(由Filed对象表示),这3个类都位于java.lang.reflect包下,并实现了java.lang.reflect.Member接口。程序可以通过Method对象执行对应的方法,通过Constructor对象对应的构造器创建实例,能通过Filed对象直接访问并修改对象的属性值。

创建对象:
通过反射来生成对象有以下两种方式:
使用Class对象的newInstance()方法来创建该Class对象对应类的实例,这种方式要求该Class对象的对应类有默认构造器,而执行newInstance()方法时实际上是利用默认构造器来创建该类的实例。
先使用Class对象获取指定的Constructor对象,在调用Constructor对象的newInstance()方法来创建该Class对象对应的实例。通过这种方式可以选择使用指定的构造器来创建实例。
通过第一种方式创建对象是比较常见的情形,因为在很多javaEE框架中都需要根据配置文件信息来创建java对象,从配置文件读取的只是某个类的字符串类名,程序需要根据该字符串来创建对应的实例,就必须使用反射。

举例:
下面程序实现了一个简单的对象池,该对象池会根据配置文件读取key-value对,然后创建这些对象,并将这些对象放入一个Hashtable中。
obj.txt:
a=java.util.Date
b=javax.swing.JFrame

ObjectPoolFactory.java:
  1. import java.util.*;
  2. import java.io.*;
  3. public class ObjectPoolFactory {
  4.         // 定义一个对象池,前面是对象名,后面是实际对象
  5.                 private Map<String ,Object> objectPool = new HashMap<>();
  6.                 // 定义一个创建对象的方法,
  7.                 // 该方法只要传入一个字符串类名,程序可以根据该类名生成Java对象
  8.                 private Object createObject(String clazzName)
  9.                         throws InstantiationException
  10.                         , IllegalAccessException , ClassNotFoundException
  11.                 {
  12.                         // 根据字符串来获取对应的Class对象
  13.                         Class<?> clazz = Class.forName(clazzName);
  14.                         // 使用clazz对应类的默认构造器创建实例
  15.                         return clazz.newInstance();
  16.                 }
  17.                 // 该方法根据指定文件来初始化对象池,
  18.                 // 它会根据配置文件来创建对象
  19.                 public void initPool(String fileName)
  20.                         throws InstantiationException
  21.                         , IllegalAccessException ,ClassNotFoundException
  22.                 {
  23.                         try(
  24.                                 FileInputStream fis = new FileInputStream(fileName))
  25.                         {
  26.                                 Properties props = new Properties();
  27.                                 props.load(fis);
  28.                                 for (String name : props.stringPropertyNames())
  29.                                 {
  30.                                         // 每取出一对key-value对,就根据value创建一个对象
  31.                                         // 调用createObject()创建对象,并将对象添加到对象池中
  32.                                         objectPool.put(name ,
  33.                                                 createObject(props.getProperty(name)));
  34.                                 }
  35.                         }
  36.                         catch (IOException ex)
  37.                         {
  38.                                 System.out.println("读取" + fileName + "异常");
  39.                         }

  40.                 }
  41.                 public Object getObject(String name)
  42.                 {
  43.                         // 从objectPool中取出指定name对应的对象。
  44.                         return objectPool.get(name);
  45.                 }

  46.                 public static void main(String[] args)
  47.                         throws Exception
  48.                 {
  49.                         ObjectPoolFactory pf = new ObjectPoolFactory();
  50.                         pf.initPool("obj.txt");
  51.                         System.out.println(pf.getObject("a"));      //①
  52.                         System.out.println(pf.getObject("b"));      //②
  53.                 }
  54. }
复制代码


如果不想利用默认构造器创建java对象,二项利用指定的构造器来创建java对象,则需要利用Constructor对象,每个Constructor对应一个构造器。
利用指定的构造器来创建java对象需要如下3个步骤:
获取该类的Class对象。
利用Class对象的getConstructor()方法来获取指定的构造器。
调用Constructor的newInstance()方法来创建java对象
例子:
  1. import java.lang.reflect.*;
  2. public class CreateJFrame
  3. {
  4.         public static void main(String[] args)
  5.                 throws Exception
  6.         {
  7.                 // 获取JFrame对应的Class对象
  8.                 Class<?> jframeClazz = Class.forName("javax.swing.JFrame");
  9.                 // 获取JFrame中带一个字符串参数的构造器
  10.                 Constructor ctor = jframeClazz
  11.                         .getConstructor(String.class);
  12.                 // 调用Constructor的newInstance方法创建对象
  13.                 Object obj = ctor.newInstance("测试窗口");
  14.                 // 输出JFrame对象
  15.                 System.out.println(obj);
  16.         }
  17. }
复制代码

由于通过反射创建对象时性能会稍微低一些,实际上只有当程序需要动态的创建某个类的对象是才会考虑使用反射,通常在开发通用性比较广的框架、基础平台时可能会大量使用反射。




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2