在开始之前,我先定义一个测试类Student,代码如下:


[Java]  view plain  copy


1. package chb.test.reflect;  
2.   
3. public class Student {  
4. private int age;  
5. private String name;  
6. public int getAge() {  
7. return age;  
8.     }  
9. public void setAge(int age) {  
10. this.age = age;  
11.     }  
12. public String getName() {  
13. return name;  
14.     }  
15. public void setName(String name) {  
16. this.name = name;  
17.     }  
18.       
19. public static void hi(int age,String name){  
20. "大家好,我叫"+name+",今年"+age+"岁");  
21.     }  
22. }<pre></pre>


一、JAVA反射的常规使用步骤

    反射调用一般分为3个步骤:

  • 得到要调用类的class
  • 得到要调用的类中的方法(Method)
  • 方法调用(invoke)

     代码示例:


[Csharp]  view plain  copy


1. Class cls = Class.forName("chb.test.reflect.Student");  
2. Method m = cls.getDeclaredMethod("hi",new Class[]{int.class,String.class});  
3. m.invoke(cls.newInstance(),20,"chb");<pre></pre>


二、方法调用中的参数类型

        在方法调用中,参数类型必须正确,这里需要注意的是不能使用包装类替换基本类型,比如不能使用Integer.class代替int.class。

       如我要调用Student的setAge方法,下面的调用是正确的:

 


[Java]  view plain  copy


1. Class cls = Class.forName("chb.test.reflect.Student");  
2. Method setMethod = cls.getDeclaredMethod("setAge",int.class);  
3. setMethod.invoke(cls.newInstance(), 15);<pre></pre>


 

       而如果我们用Integer.class替代int.class就会出错,如:


[Java]  view plain  copy


1. Class cls = Class.forName("chb.test.reflect.Student");  
2. Method setMethod = cls.getDeclaredMethod("setAge",Integer.class);  
3. setMethod.invoke(cls.newInstance(), 15);<pre></pre>


 

       jvm会报出如下异常:


[HTML]  view plain  copy


1. java.lang.NoSuchMethodException: chb.test.reflect.Student.setAge(java.lang.Integer)  
2.     at java.lang.Class.getDeclaredMethod(Unknown Source)  
3. <pre></pre>

 

三、static方法的反射调用

 

       static方法调用时,不必得到对象示例,如下:


[Java]  view plain  copy



1. Class cls = Class.forName("chb.test.reflect.Student");  
2. Method staticMethod = cls.getDeclaredMethod("hi",int.class,String.class);  
3. staticMethod.invoke(cls,20,"chb");//这里不需要newInstance  
4. //staticMethod.invoke(cls.newInstance(),20,"chb");<pre></pre>


四、private的成员变量赋值

    如果直接通过反射给类的private成员变量赋值,是不允许的,这时我们可以通过setAccessible方法解决。代码示例:


[Java]  view plain  copy


1. Class cls = Class.forName("chb.test.reflect.Student");  
2. Object student = cls.newInstance();//得到一个实例  
3. Field field = cls.getDeclaredField("age");  
4. field.set(student, 10);  
5. System.out.println(field.get(student));<pre></pre>


 

     运行如上代码,系统会报出如下异常:


[HTML]  view plain  copy


1. java.lang.IllegalAccessException: Class chb.test.reflect.TestClass can not access a member of class chb.test.reflect.Student with modifiers "private"  
2.     at sun.reflect.Reflection.ensureMemberAccess(Unknown Source)  
3.     at java.lang.reflect.Field.doSecurityCheck(Unknown Source)  
4.     at java.lang.reflect.Field.getFieldAccessor(Unknown Source)  
5.     at java.lang.reflect.Field.set(Unknown Source)  
6. <pre></pre>

  


    解决方法:


[Java]  view plain  copy



1. Class cls = Class.forName("chb.test.reflect.Student");  
2. Object student = cls.newInstance();  
3. Field field = cls.getDeclaredField("age");  
4. field.setAccessible(true);//设置允许访问  
5. field.set(student, 10);  
6. System.out.println(field.get(student));<pre></pre>


    其实,在某些场合下(类中有get,set方法),可以先反射调用set方法,再反射调用get方法达到如上效果,代码示例:


[Java]  view plain  copy



    1. Class cls = Class.forName("chb.test.reflect.Student");  
    2. Object student = cls.newInstance();  
    3.   
    4. Method setMethod = cls.getDeclaredMethod("setAge",Integer.class);  
    5. setMethod.invoke(student, 15);//调用set方法  
    6.               
    7. Method getMethod = cls.getDeclaredMethod("getAge");  
    8. System.out.println(getMethod.invoke(student));//再调用get方法



    /*
     * 将父类所有的属性COPY到子类中。
     * 类定义中child一定要extends father;
     * 而且child和father一定为严格javabean写法,属性为deleteDate,方法为getDeleteDate
     */
        public static void fatherToChild (Object father,Object child)throws Exception{
            if(!(child.getClass().getSuperclass()==father.getClass())){
                throw new Exception("child不是father的子类");
            }
            Class fatherClass= father.getClass();
            Field ff[]= fatherClass.getDeclaredFields();
            for(int i=0;i<ff.length;i++){
                Field f=ff[i];
                Method m=fatherClass.getMethod("get"+upperHeadChar(f.getName()));
                Object obj=m.invoke(father);
                f.setAccessible(true);
                f.set(child,obj);
            }
        }