Chinaunix首页 | 论坛 | 博客
  • 博客访问: 94213
  • 博文数量: 59
  • 博客积分: 1400
  • 博客等级: 上尉
  • 技术积分: 385
  • 用 户 组: 普通用户
  • 注册时间: 2009-05-29 15:12
文章分类

全部博文(59)

文章存档

2011年(1)

2009年(58)

我的朋友

分类: Java

2009-06-25 19:20:23

Java反射机制通过JVM运行时动态获取类信息以及动态调用对象的方法。其实反射并不像我们想象的那么神秘,复杂。它通过java.lang.Class以及java.lang.reflect包的API实现的反射功能。我们在Spring AOP,JDBC数据库加载驱动都有用到反射机制。下面通过几段代码示例看看reflection究竟是如何工作的。
Java代码 复制代码
  1. package com.me.reflection;   
  2. import java.lang.reflect.*;   
  3.   
  4. public class DumpMethods {   
  5.     public static void main(String args[]) {   
  6.         try {   
  7.             Class c = Class.forName("java.lang.String"]);//1   
  8.             Method m[] = c.getDeclaredMethods();   
  9.             for (int i = 0; i < m.length; i++)   
  10.                 System.out.println(m[i].toString());   
  11.         } catch (Throwable e) {   
  12.             System.err.println(e);   
  13.         }   
  14.     }   
  15. }  


大家对代码1处蛮眼熟吧,没错,在JDBC数据库加载驱动中用到了。这个程序使用 Class.forName 载入指定的类,然后调用 getDeclaredMethods 来获取这个类中定义了的方法列表。java.lang.reflect.Method是用来描述某个类中单个方法的一个类。
总结:获得指定类的方式有(1)Class.forName("") (2).class 如int.class (3)包装类.TYPE 如:Integer.TYPE

Java代码 复制代码
  1. package com.me.reflection;   
  2.   
  3. import java.lang.reflect.*;   
  4.   
  5. public class MethodDemo {   
  6.     private int f1(Object p, int x) throws NullPointerException {   
  7.         if (p == null)   
  8.             throw new NullPointerException();   
  9.         return x;   
  10.     }   
  11.   
  12.     public static void main(String args[]) {   
  13.         try {   
  14.             Class cls = Class.forName("com.me.reflection.MethodDemo");   
  15. //获得指定类的所有方法。通过getMethods()返回指定类所有公共方法   
  16.             Method methlist[] = cls.getDeclaredMethods();   
  17.             for (int i = 0; i < methlist.length; i++) {   
  18.                 Method m = methlist[i];   
  19.                 System.out.println("name = " + m.getName());   
  20.                 System.out.println("decl class = " + m.getDeclaringClass());   
  21. //获得每个方法的参数类型类表数组   
  22.                 Class pvec[] = m.getParameterTypes();   
  23.                 for (int j = 0; j < pvec.length; j++)   
  24.                     System.out.println("param #" + j + " " + pvec[j]);   
  25.            }   
  26.         } catch (Throwable e) {   
  27.             System.err.println(e);   
  28.         }   
  29.     }   
  30. }  


这个程序首先取得 MethodDemo类的描述,然后调用 getDeclaredMethods 来获取一系列的 Method 对象,它们分别描述了定义在类中的每一个方法,包括 public、protected package和private方法等。如果你在程序中使用getMethods来代替getDeclaredMethods,你还能获得继承来的各个方法的信息。

Java代码 复制代码
  1. package com.me.reflection;   
  2.   
  3. import java.lang.reflect.*;   
  4.   
  5. public class ConstructorDemo {   
  6.     public ConstructorDemo () {   
  7.     }   
  8.   
  9.     protected ConstructorDemo (int i, double d) {   
  10.     }   
  11.   
  12.     public static void main(String args[]) {   
  13.         try {   
  14.             Class cls = Class.forName("com.me.reflection.ConstructorDemo");   
  15. //获得指定类的所有构造方法。通过getConstructors()返回指定类所有公共构造方法   
  16.             Constructor ctorlist[] = cls.getDeclaredConstructors();   
  17.             for (int i = 0; i < ctorlist.length; i++) {   
  18.                 Constructor ct = ctorlist[i];   
  19.                 System.out.println("name = " + ct.getName());   
  20.                 System.out.println("decl class = " + ct.getDeclaringClass());   
  21. //获得每种构造方法的参数类型类表数组   
  22.                 Class pvec[] = ct.getParameterTypes();   
  23.                 for (int j = 0; j < pvec.length; j++)   
  24.                     System.out.println("param #" + j + " " + pvec[j]);   
  25.            }   
  26.         } catch (Throwable e) {   
  27.             System.err.println(e);   
  28.         }   
  29.     }   
  30. }  

获取类构造器的用法与上述获取方法的用法类似。
Java代码 复制代码
  1. package com.me.reflection;   
  2. import java.lang.reflect.*;   
  3.   
  4. public class FieldDemo{   
  5.     private double d;   
  6.     public static final int i = 37;   
  7.     String s = "testing";   
  8.   
  9.     public static void main(String args[]) {   
  10.         try {   
  11.             Class cls = Class.forName("com.me.reflection.FieldDemo");   
  12.             Field fieldlist[] = cls.getDeclaredFields();   
  13.             for (int i = 0; i < fieldlist.length; i++) {   
  14.                 Field fld = fieldlist[i];   
  15.                 System.out.println("name = " + fld.getName());   
  16.                 System.out.println("decl class = " + fld.getDeclaringClass());   
  17.                 System.out.println("type = " + fld.getType());   
  18.                 int mod = fld.getModifiers();   
  19.                 System.out.println("modifiers = " + Modifier.toString(mod));   
  20.                 System.out.println("-----");   
  21.             }   
  22.         } catch (Throwable e) {   
  23.             System.err.println(e);   
  24.         }   
  25.     }   
  26. }  

这个例子和前面那个例子非常相似。例中使用了一个新东西 Modifier,它也是一个 reflection 类,用来描述字段成员的修饰语,如“private int”。这些修饰语自身由整数描述,而且使用 Modifier.toString 来返回以“官方”顺序排列的字符串描述 (如“static”在“final”之前)。

以上显示了通过reflection获得类信息的这种用法。那么如何动态创建类对象,调用方法呢
Java代码 复制代码
  1. package com.me.reflection;   
  2.   
  3. import java.lang.reflect.*;   
  4.   
  5. public class ReflectionApp {   
  6.     public ReflectionApp(){}   
  7.   
  8.     public ReflectionApp(int a,int b){   
  9.        System.out.println("a = " + a + " b = " + b);   
  10.     }   
  11.        
  12.     public int add(int a, int b) {   
  13.         return a + b;   
  14.     }   
  15.     public static void main(String args[]) {   
  16.         try {   
  17.             Class cls = Class.forName("com.me.reflection.ReflectionApp");   
  18.    Class partypes[] = new Class[2];   
  19.             partypes[0] = Integer.TYPE;   
  20.             partypes[1] = Integer.TYPE;   
  21. //创建类对象 如果指定类只有默认构造方法,我们可通过cls.newInstance()直接生成类对象,只有Class和Constructor这两个类可以直接生成类对象            
  22.             Constructor ct = cls.getConstructor(partypes);   
  23.             Object arglist[] = new Object[2];   
  24.             arglist[0] = new Integer(37);   
  25.             arglist[1] = new Integer(47);   
  26. [color=red]//注意:Class#getConstructor和Constructor#newInstance方法参数类型是一致的[/color]   
  27.             ReflectionApp ra = (ReflectionApp)ct.newInstance(arglist);   
  28. //获得指定类指定方法   
  29.             Method meth = cls.getMethod("add", partypes);   
  30. //动态调用类方法:通过invoke(指定类对象,方法参数类型列表)方法              
  31.             Object retobj = meth.invoke(ra, arglist);   
  32.             Integer retval = (Integer) retobj;   
  33.             System.out.println(retval.intValue());   
  34.         } catch (Throwable e) {   
  35.             System.err.println(e);   
  36.         }   
  37.     }   
  38. }  

很多同学认为创建一个对象调用一下方法怎么写这么麻烦,但是使用这种方法可以在程序运行时动态地创建对象,动态调用方法,而不是在编译的时候创建对象,这一点非常有价值。大家可以参照Java API研究下如何改变属性值等其他功能。动态创建数组将在以后的文章写到。
阅读(492) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~