勇于挑战
不畏艰辛
posts - 22,comments - 0,trackbacks - 0
Java 反射机制是指Java程序可以在执行期载入,探知,使用编译期间完全未知的classes.这句话可能有点难以理解,我们可以通过一个例子来看。在Java程序中我们经常会用到这样一条语句来创建一个对象。Date date = new Date();在这条语句中date的类型(Java.util.Date)在编译时 已经确定。那么,有没有办法使我们把对象类型的确定时间由编译转到运行,答案是肯定的。这就是Java反射机制所提供的便利。而且它不单单可以生成对象还可以获取Field,对Field设值,及调用方法等。

  谈及Java反射机制就一定要知道一个名为“Class”的类,它是Java反射机制的基础。“Class”和其它类一样继承于Object类,它的实例对象用来描述Java运行时的一种类型,接口,或者原始类型(比如int).“Class”的实例要由JVM创建,它没有公用的构造方法。下面我们来看一下如何获得"Class"类实例。

  主要有三种方法。

  一,通过Class类的静态方法forName获取。Class cla = Class.forName("java.lang.String");

  二,通过.Type或.class属性获得。Class cla = String.class;Class cla1 = int.Type;

  三,通过实例变量的getClass方法获得。String s = ""; Class cla = s.getClass();

  如上所示实例对象cla就是对String类型的描述,通过它我们就可以创建一个String实例,并调用其中的方法。下一篇我将通过一个例子来展示如何使用Java反射机制。

下面我以顾客买相机为例来说明Java反射机制的应用。例子中涉及的类和接口有:

  Camera接口:定义了takePhoto()方法。

  Camera01类:一种照相机的类型,实现Camera接口。

  Camera02类:另一种照相机的类型,实现Camera接口。

  Seller类:卖照相机。

  Customer类:买相机,有main方法。

  所有类都放在com包里

  程序如下:

  public interface Camera {

  //声明照相机必须可以拍照

  public void takePhoto();

  }

  public class Camera01 implements Camera {

  private final int prefixs =300;//300万象素

  private final double ptionZoom=3.5; //3.5倍变焦

  public void takePhoto() {

  System.out.println("Camera01 has taken a photo");

  }

  }

  类似的有

  public class Camera02 implements Camera {

  private final int prefixs =400;

  private final double ptionZoom=5;

  public void takePhoto() {

  System.out.println("Camera02 has taken a photo");

  }

  }

  顾客出场了

  public class Customer {

  public static void main(String[] args){

  //找到一个售货员

  Seller seller = new Seller();

  //向售货员询问两种相机的信息

  seller.getDescription("com.Camera01");

  seller.getDescription("com.Camera02");

  //觉得Camera02比较好,叫售货员拿来看

  Camera camera =(Camera)seller.getCamera("com.Camera02");

  //让售货员拍张照试一下

  seller.testFuction(camera, "takePhoto");

  }

  }

  Seller类通过Java反射机制实现

  import java.lang.reflect.Field;

  import java.lang.reflect.Method;

  public class Seller {

  //向顾客描述商品信息

  public void getDescription(String type){

  try {

  Class cla = Class.forName(type);

  //生成一个实例对象,在编译时我们并不知道obj是什么类型。

  Object bj = cla.newInstance();

  //获得type类型所有已定义类变量及方法。

  Field[] fileds = cla.getDeclaredFields();

  Method[]methods = cla.getDeclaredMethods();

  System.out.println("The arguments of this Camera is:");

  for(int i=0;i

  fileds[i].setAccessible(true);

  //输出类变量的定义及obj实例中对应的值

  System.out.println(fileds[i]+":"+fileds[i].get(obj));

  }

  System.out.println("The function of this Camera:");

  for(int i=0;i

  //输出类中方法的定义

  System.out.println(methods[i]);

  }

  System.out.println();

  } catch (Exception e) {

  System.out.println("Sorry , no such type");

  }

  }

  //使用商品的某个功能

  public void testFuction(Object obj,String function){

  try {

  Class cla = obj.getClass();

  //获得cla类中定义的无参方法。

  Method m = cla.getMethod(function, null);

  //调用obj中名为function的无参方法。

  m.invoke(obj, null);

  } catch (Exception e) {

  System.out.println("Sorry , no such function");

  }

  }

  //拿商品给顾客

  public Object getCamera(String type){

  try {

  Class cla = Class.forName(type);

  Object bj = cla.newInstance();

  return obj;

  } catch (Exception e) {

  System.out.println("Sorry , no such type");

  return null;

  }

  }

  }

上一篇中,通过例子我们知道了如何利用反射机制创建对象,获得类变量和调用方法等。创建对象的语句是 Class cla = Class.forName(type); Object bj = cla.newInstance(); 这里newInstance()实际上是使用了该类的默认无参构造方法。如果我们要调用其它的构造方法就要稍微复杂一点。比如我们要创建一个StringBuffer对象,用new 操作符应该是StringBuffer br = new StringBuffer("example");用反射机制则要有以下步骤。

  首先,获得StringBuffer类的描述。

  Class cla = Class.forName("java.lang.StringBuffer");

  其次,要创建参数类型数组Class[] 。

  Class[] paraTypes = new Class[1];paraTypes[0]=String.class;

  然后,通过cla 和 paraTypes 获得Constructor 对象。

  Constructor constructor = cla.getConstructor(paraTypes);

  接着,创建传入的参数列表Object[]。

  Object[] paraLists = new Object[1]; paraLists[0]="color";

  最后,得到我们所要得对象。Object bj = constructor.newInstance(paraLists);

  如果我们paraTypes及paraLists设为null或长度为0,就可以用上述步骤调用StringBuffer的无参构造方法。类似地,我们可以调用对象中的有参方法。比如我们做如下操作br.insert(4, 'u');用反射机制实现如下。

  Class[] paratypes = new Class[]{int.class,char.class};

  Method method = cla.getMethod("insert", paratypes);

  Object[] paralists = new Object[]{4,'u'};

  method.invoke(obj, paralists);

  反射机制给予我们运行时才确定对象类型的便利,然而它也有显著的缺点。

  1,代码笨拙冗长。比如本来一句br.insert(4, 'u');可以解决的问题现在要用到四句。

  2,损失了编译时类型检查的好处。这使得你要对付更多的异常。

  3,性能损失。用反射机制运行的时间更久。

  <>中给出的建议是“普通应用不应在运行时刻以映像方式访问对象,只是在很有限的情况下使用“。那么在什么地方会用到反射机制呢。已有的较熟悉应用是我们的IDE及一些框架。比如eclipse,编程时ctrl+space弹出的建议就是用到反射机制。比如Spring读取配置文件后生成对应的对象。还有RPC系统也会用到。对于一般的应用软件,你可以在工厂方法中用到它。

posted on 2009-05-14 13:17 郭鹏 阅读(288) 评论(0)  编辑  收藏 所属分类: JAVA

只有注册用户登录后才能发表评论。


网站导航: