`

Java反射入门

    博客分类:
  • java
阅读更多
Java反射入门
Java为我们提供了反射机制,反射——在生物中被这样解释:动物通过中枢神经系统对刺激的一种应答式反应,在物理中它被这样解释:声波、光波或其他电磁波遇到障碍物或别种媒质面而折回,那么它在Java中又该怎么解释呢?首先我们来看看它能做什么:
1.         在运行时判断任意一个实例的所属类。
2.         在运行时构造任意一个类的实例。
3.         在运行时获取任意类所具有的属性和方法。
4.         在运行时调用任意对象的方法。
不知道大家有没有注意到“运行时”这三个字,它能让我们的程序更加动态,更加的灵活,好了,废话少说,我们一个一个来实现上面所说的功能。
在解决以上问题之前,我们先看看java为我们提供了哪些类来实现反射:
Class:它代表一个类,JVM每加载一个类都会实例一个相应的Class对象,如何取得它我们后话再讲。
Field:它代表类的属性。
Method:它代表类的方法。
Constructor:它代表类的构造方法。
1.在运行时判断任意一个实例的所属类。
首先我们准备一个用于测试的Javabean:
package vo;
public class UserVo {
           private String name;
           public UserVo(){}
           public String getName(){
              return this.name;
           }
           public void setName(String name){
              this.name=name;
           }
}
我们将围绕这个类来进行测试。我们再写一个类名叫:TestReflection,代码如下:
package reflection;
import vo.UserVo;
public class TestReflection {
           /**
            * 打印类的信息
            */
           public void refClassInfo(Object o){
              Class c=o.getClass();
              System.out.println(c.getName());
           }
           public static void main(String[] args) {
              UserVo t=new UserVo();
              new TestReflection().refClassInfo(t);
           }
}
现执行下看看效果,是不是动态的获取了类名?接着我们来看看它的实现。
           public void refClassInfo(Object o){
              Class c=o.getClass();
              System.out.println(c.getName());
           }
主要就是这个方法了,它有一个Object型的参数,在执行它之前我们并不知道它是属于那个类的,但程序运行时我们就可以通过Class.getName()这个方法来得到。
前面我们说过Class代表一个类,我们在这个例子中,通过调用对象的getClass(),来获取此对象的Class对象,既然它代表类,那么它肯定拥有这个类的所有信息,getName()这个方法就能获得它的类名。
后面的一切操作都是以它为基础的,在java中如果要反射,我们就得现获得Class对象,这个道理很简单,如果你连哪个类都不知道,你怎么去找它的方法?呵呵。
2.在运行时构造任意一个类的实例。
           在这个例子中,假设我们知道类名,但没有这个对象,我们通过反射机制来动态的获取一个对象。
           public static Object getInstance(String className){
              try {
                  Class c=Class.forName(className);
                  return c.newInstance();
              } catch (ClassNotFoundException e) {
                  e.printStackTrace();
              } catch (InstantiationException e) {
                  e.printStackTrace();
              } catch (IllegalAccessException e) {
                  e.printStackTrace();
              }
              return null;
           }
           这个例子中,我们接触一种新的获取Class的方法,通过Class.forName(String className)这个方法,得到Class对象后,再调用它的newInstance()即可获得此类的对象。
           我们怎么调用这个方法呢?
           public static void main(String[] args) {
              UserVo t=(UserVo)TestReflection.getInstance("vo.UserVo");
           }
           上面我们确实获取了实例,但这种方法有个缺点,就是只支持无参的构造函数,如果我们要实例的类它的构造函数是有参的我们该怎么办,这里我们要用到Constructor类,还记得它吗?前面说过它代表构造方法,我们来看代码。
           public static Object constructInstance(String className){
              try {
                  Class c=Class.forName(className);
                  Class[] paramList={String.class};//参数列表
                  Constructor ctor=c.getConstructor(paramList);
                  Object[] param={"hello"};
                  return ctor.newInstance(param);
              } catch (Exception e) {
                  e.printStackTrace();
              }
              return null;
           }
           首先我先介绍下String.class这个写法,这种方法也可以获取某类的Class对象,这里获取的String的Class对象,至此我们学习三种获取Class的方法。
1.         Object.getClass();
2.         Class.forName(className);
3.         new Object().class;
——接下来我们继续分析代码。
构造好参数列表(形参)后,我们可以通过这个这个参数列表来找一个构造方法:
Constructor ctor=c.getConstructor(paramList);
Class类的getConstructor()方法可以获取指定参数列表的构造方法类:Constructor,Constructor类同样有一个newInstance()的方法,只不过这次得传参数了,这里必须传Object的数组,但我们构造方法的参数是String型的怎么办?根据多态的特性,我们知道父类的引用可以指向子类的对象,这里我们只需在Object数组中放入String的对象就OK了。
Object[] param={"hello"};
           最后调用ctor.newInstance(param);获得该对象的实例。
           要使用本函数,className所对应的类必须有一个有参的构造方法才行,否则会抛出异常。
3.在运行时获取任意类所具有的属性和方法。
           这一节我们讨论如何动态的获取属性和方法,首先我们先讲获取属性吧。
           Class类提供我们四个方法获取某类的属性:
           Field[] getDeclaredFields() 获取所有此类自己声明的字段,包括任何访问级别。
Field getDeclaredField(String fieldName) 获取指定名字的自己申明的对象。
Field[] getFields() 获取所有(包括父类的)访问级别为public的字段。
Field getField(String fieldName) 获取指定名字访问级别为public的字段,包括父类的。
看完API后,我相信大家应该能够写出来了,我就附上一个例子吧。
           public static void showFields(Object o){
              Class c=o.getClass();
              Field[] fields=c.getDeclaredFields();
              for(Field f : fields){
                  try {
                     System.out.println("类型:"+f.getGenericType().toString()
                            +"字段名:"+f.getName()
                            +"值"+f.get(o));
                  } catch (Exception e) {
                     e.printStackTrace();
                  }
              }
}
           上面的例子有读取字段的值,但如果访问级别不够将会出异常,如要测试,请把相应的字段访问级别改为public.
           有关Field类请大家自行查询帮助文档,本文只是起个抛砖引玉的作用,很多东西还得考大家自己去帮助文档中找。
           接下来我们学习下动态获取某类的方法。在Class类中也提供了相应的方法,这组方法与获取Field的方法相似,我们来看看:
           Method getDeclaredMethod(String name, Class... parameterTypes)
           Method[] getDeclaredMethods()
           Method getMethod(String name, Class... parameterTypes)
           Method[] getMethods()
            对这些方法我就不多做介绍了,和获取Field的方法是对应的,请大家参阅JAVA API文档,我给大家一个例子吧:
               public static void showMethod(Object o){
                  Class c=o.getClass();
                  Method[] methods=c.getDeclaredMethods();
                  for(Method me : methods){
                      System.out.println(me.getName());
                   }
               }
           它可以打印出指定对象属于类中申明定义的所有方法(不包括父类的)。
4.在运行时调用任意对象的方法。
           最实用的来了,动态调用方法。通过它我们可以实现很多很智能的东西,比如Hibernate中的Session,只要调用它的save方法,把一个VO对象放进去它就能帮我们自动生成sql语句,并将其插入到数据库中,酷吧!呵呵,学完这个特性后,我们完全可以实现同样的功能。
           我们来看个例子:
         public static void invokeMethod(Object o){
            Class c=o.getClass();
            try {
Method method=c.getMethod("setName", new Class[]{String.class});
                method.invoke(o, new Object[]{"yjgoo"});
            } catch (Exception e) {
                e.printStackTrace();
            }
         }
           这个例子演示了动态的调用方法的方法,首先得到Method对象,这里使用Class对象的getMethod()方法,它有两个参数,第一个是要获取的方法名,第二个是这个方法的参数类型,这里用的是String型,这里应该没问题吧?有问题的话把代码多琢磨下,写下。
           找到Method对象后,调用它的invoke()方法,它也需要两个参数,第一个是从中调用这个方法的对象,这里写的是o,因为我们要调用o的setName方法,第二个参数是参数,也是Object的数组,这里setName方法需要的参数是String对象,就传一个String的对象就可以了。
           全文就OVER了,不知道大家都看懂了没有,呵呵,希望大家多去看看java API文档,在那里面可以详细的了解反射,通过反射可以做很多事情,本文只介绍了很小一部分。


其中主方法完整的如下:         public static void main(String[] args) {
              //动态构造UserVo对象
              UserVo uv=(UserVo)TestReflection.getInstance("vo.UserVo");
              TestReflection.refClassInfo(uv);//动态获取uv对象是哪个类的实例
              System.out.println("所有的方法:");
              TestReflection.showMethod(uv);//显示uv对象所属类自己定义的所有方法
              uv.setName("no name");
              TestReflection.showFields(uv);//显示uv对象的所有属性和值
              TestReflection.invokeMethod(uv);//动态执行方法,调用setName方法,改变name的值
              TestReflection.showFields(uv);//再显示
           }
源文件来自:http://hi.baidu.com/cxmjjyizuxbcuvd/item/146688cbda7d7c2c46d5c0d5
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics