分享

java 反射机制

 navy_lu 2010-08-05
Java的反射机制可以动态的加载类,实例化对象,动态的调用对象的方法等等。可以说Java的反射机制异常的强大。而且在很多的高级框架中都得到了应用。也可能说,Java的反射是高级框架功能实现的重要的一部分,所以,学好Java的反射机制对于我们高级框架的深入学习尤为重要。

   Java中有的java.lang.Class对象代表Java应用程序运行时所加载的类或者接口的实例。Java中的每一个类都有一个java.lang.Class对象向对应。要获得java.lang.Class的对象有两种办法,直接通过类的.class来获得,或通过类实例例化出来的对象的getClass()方法获得。
Java代码 复制代码
  1. //第一种   
  2. Class clazz=String.class;   
  3. //第二种          
  4. String str="work";   
  5. Class clazz1=str.getClass();  

这样,我们就获得了String类的Class实例。有了Class实例,我们就可以对其相对应的类进行实例化对象,方法的调用,域的修改等操作。

我们还可以通过Class.forName()方法来加载类,获得Class的实例。在写数据库的时候,我会都接触到,用它来加载数据库驱动类。forName()还有个重载的方法,除了传递一个类,还可以传递一个布尔型的值,如果为false,那么将不会初始化加载的类(一般用到它是因为类中的静态域的问题)。

我们还可以通过类的加载器,ClassLoader实例的loadClass()方法来加载类。获得ClassLoader的方法:
ClassLoader loader=类名.class.getClassLoader();
下面我们对类的加载器进行下简要的分析:
每个类加载器再加载类之前,会先让父类加载器先加载,如果父类加载器找不到要加载的类,再交给自己来加载。Java中有3个类加载器,BootstrapLoader,ExtClassLoader,AppClassLoader(SystemLoader)。他们会按照BootstrapLoader -> ExtClassLoader -> AppClassLoader这个顺序去加载类,如果找不到类,则会丢出NotClassDefFoundError异常。用ClassLoader来加载类是,不会初始化类的静态区域,只有再真正使用到这个类的时候,才初始化静态区域。前面说过,每个类有一个Class的实例对象,但是,如果同一个类,被两个加载器都加载过,就会有两个Class的实例与它对应。


用反射生成对象,我们可以调用Class中的newInstance()方法来生成对象,例如
Java代码 复制代码
  1. Class clazz=String.class;   
  2. //生成一个Object类型的对象   
  3. Object obj=clazz.newInstance();  

生成的对象都是Object类型的。但是有一点要注意,用这种方法生成对象,类中必须有一个无参的构造器。另外,还有一种生成对象的办法,用java.lang.reflect.Constructor这个类来生成对象。用这种方法来生成对象可以不必有无参的构造器,我们以String类为例,用Constructor来实例化一个String类的对象,用其public String(String arg0)构造器为例子:
Java代码 复制代码
  1. //获得String的Class实例   
  2. Class clazz=String.class;   
  3. //创建一个数组,这个数组用来放要实例化对象的构造器里的参数类型   
  4. Class[] param=new Class[1];   
  5. //放入构造器中的参数类型,如果有多个,按顺序放入   
  6. param[0]=String.class;   
  7. //实例化一个构造器对象,并把放着构造器参数类型的数组作为参数传进去   
  8. Constructor constructor=clazz.getConstructor(param);   
  9. //创建一个Object数组,用于放构造器中对应的值   
  10. Object[] obj=new Object[1];   
  11. //将值放入到数组中,这里要注意,param数组中放入的是什么类型,这里就要按顺序放入   
  12. obj[0]="zhang3";   
  13. //实例化对象,并把放着构造器要传入的参数的数组传到方法中   
  14. String str=(String)constructor.newInstance(obj)  

这样,我们就通过java.lang.reflect.Constructor实例化出来了String类型的对象。

用反射调用方法,通过java.lang.reflect.Method类,我们来实现对方法的调用,代码如下:
Java代码 复制代码
  1. //实例化一个方法的对象,arg0是方法名,arg1是方法的参数类型,要是多个就传数组   
  2. Method method=clazz.getMethod(arg0, arg1);   
  3. //方法的调用,arg0是有次方法的对象,arg1是传入方法中的值   
  4. method.invoke(arg0, arg1);  

上面的两行代码是最主要的,下面我贴出一个完整例子的代码,对照的看下,马上就明白,假设有一个Student类,它有一个setName方法,方法参数类型为String:
Java代码 复制代码
  1. Class clazz=Student.class;   
  2. Object obj=clazz.newInstance();   
  3. Class[] param={String.class};   
  4. Method method=clazz.getMethod("setName", param);   
  5. Object[] value={"zhang3"};   
  6. method.invoke(obj, value);  

以上便是反射对方法的调用,基本上与实例化对象大同小异。

用反射修改域,通过java.lang.reflect.Field来实现,下面我直接贴出完整例子的代码,还是以Student类为例:
Java代码 复制代码
  1. Class clazz=Student.class;   
  2. Object obj=clazz.newInstance();   
  3. //获得一个域的实例,getField()方法中的参数为域的名字   
  4. Field name=clazz.getField("name");   
  5. //*如果你的域修饰为private,那么必须调用setAccessible("true")才能对其修改   
  6. name.setAccessible("true");   
  7. //第一个参数是有此域的对象,第二个是值,这个方法是通用的,不管你的域类型是什么   
  8. name.set(obj, "zhang3");  


Java的反射机制非常的强大,在这里我只是对其一些基本的功能如加载类,实例化对象,对类中方法的调用等功能进行了简单的讲解和分析。再后面,我还会对反射中的代理进行简要概述

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多