| 本帖最后由 佟亚鹏 于 2012-9-16 12:53 编辑 
 
 楼主理解反射,首先要了解反射的基石Class这个类 Java类用来描述一类事物的共性,而Class类就是描述了一个Java类的相关信息的,Class 类的实例表示正在运行的 Java 应用程序中的类和接口。Class类描述的信息有,类的名字、类的访问属性、类锁属于的包名、字段名称的列表、方法名称的列表等。在程序的运行期间,一旦我们想生成那个类的一个对象,用于执行程序的Java 虚拟机首先就会检查那个类型的Class 对象是否已经载入。如果没有载入,JVM 就会查找同名的.class 文件,并将其载入,一旦那个类型的Class 对象进入内存,就以它为模版来创建那一类型的所有对象。 
 以java.lang.String这个类来说明,有两种方式可以获得一个Java类的字节码,就是它对应的Class对象 第一种方法是通过类中一个静态的字段class获得   String.class 第二种方法是通过Java类的基类Object所提供的getClass方法  new String().getClass() 下面的这段代码打印的结果是true,表明每个Java类的字节码在程序中只有一份,这也很容易理解,有一份就够了  public static void main(String[] args) {    //通过上述的第一种方法拿到Class对象Class c1 = String.class;
   //通过上述的第二种方法拿到Class对象Class c2 = new String().getClass();
   //比较着两份字节码是否相同System.out.println(c1 == c2);
 }
 Java 基本的 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也有自己的 Class 对象 ,这点Java api中Class类的描述中有提到,可以通过类型+.class获得,如int.class、void.class,这九个对象时Java预定义的Class实例对象。数组类型也有他们对象的Class对象,如:int[].class、long.class等。总的来说,只要源程序中出现的类型,都有各自的Class实例对象。 可以通过Class的静态方法forName获得一个Java对象,它的参数是一个Java类的完整名(包名+类名),如果找不到这个类会抛出ClassNotFound这个异常, public static void main(String[] args) {try {
 //拿到java.lang.String这个类的字节码
 Class strCls = Class.forName("java.lang.String");
 //通过这份字节码创建一个String的对象
 String str = (String) strCls.newInstance();
 //打印String对象str的长度
 System.out.println(str.length());
 } catch (ClassNotFoundException e) {
 e.printStackTrace();
 } catch (InstantiationException e) {
 e.printStackTrace();
 } catch (IllegalAccessException e) {
 e.printStackTrace();
 }
 }
 上面这段代码演示了使用Class.ForName获得一个String对象,程序的打印结果为0,表示str不是一个空的引用,否则调用它的length方法就会抛出空指针异常,因此成功的拿到了一个String对象 Class类的常用方法有 public Annotation[] getAnnotations()  返回它所表示的类或接口上存在的所有注释的数组 public ClassLoader getClassLoader()  返回该类的类加载器 public Constructor<T> getConstructor(Class<?>... parameterTypes)  参数为构造函数的类型的Class,返回一个表示类的构造方法的 Constructor 对象 public Field getDeclaredField(String name) 返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。name 参数是一个 String,它指定所需字段的简称 public Method[] getMethods()  返回一个包含某些 Method 对象的数组 public boolean isArray() 判定此 Class 对象是否表示一个数组类 public boolean isInterface() 判定指定的 Class 对象是否表示一个接口类型。  public boolean isPrimitive()  判定指定的 Class 对象是否表示一个基本类型 。。。。。反射技术就是围绕这这些方法进行的。 现在知道了Class类用来是描述Java类的,java类中的,构造方法、包、成员变量、所拥有的方法,Java也都提供了相应的描述对象,分别是Constructor、Package、Field、Method,需要反射字段就先获得这个字段,然后再某个对象上设值,修改值,等等,脑海中有这个过程反射就很容易了解了,给你几个例子 通过反射把某个对象身上的值改掉 一般的方法调用和反射调用复制代码public static void main(String[] args) throws Exception {  
  //new出测试的对象
  ReflectPoint p1 = new ReflectPoint(520,909);
  //获得ReflectPoint类的成员变量y
  Field field = ReflectPoint.class.getDeclaredField("x");
  //私有成员默认是不可访问的,要设置为可以访问
  field.setAccessible(true);
  //得到p1对象,字段y的值
  System.out.println("before: " + field.get(p1));
  //把p1对象的x值修改为0
  field.set(p1, 0);
  System.out.println("after: " + field.get(p1));
 }
通过这个构造方法获得对象复制代码public static void main(String[] args) throws Exception {  
  String str = "黑马程序员训练营";
  Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);
  //若要获得str的第二个字符,通常的方式为
  System.out.println(str.charAt(2));
  //通过反射的方式
  System.out.println(charAt.invoke(str, 2));
 }
上面程序的打印结果是:黑马程序员训练营复制代码public static void main(String[] args) throws Exception {  
  //获得String类的以一个字符数组,构造出String对象的构造方法
  Constructor c1 = String.class.getConstructor(char[].class); 
  char[] chars = {'黑','马','程','序','员','训','练','营'};
  //调用c1的newInstance方法,把chars传递过去,返回的是Object,把它强制转换为String类型
  String str1 = (String)c1.newInstance(chars);
  System.out.println(str1);
 }
 
 |