Java Reflection
     Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法
反射相关的主要API:
java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Constructor:代表类的构造方
Class 类:
       在Object类中定义了以下的方法,此方法将被所有子类继承: public final Class getClass()
Class 类的常用方法:
实例:
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class TestReflection {
    //有了反射,可以通过反射创建一个类的对象,并调用其中的属性、方法
    
    public void test3(){
        Person p=new Person();
        Class cla=p.getClass();//通过运行时类的对象,调用其getClass方法,返回其运行时类
        System.out.println(cla);
    }
      
    public void test2() throws Exception{
     Class cla=Person.class;
     
     //1.创建cla对应的运行时类Person类的对象
     Person p=(Person)cla.newInstance();
     System.out.println(p);
     
     //2.通过反射调用运行时类的指定的属性
     //2.1
     Field f1=cla.getField("name");
     f1.set(p, "LiMing");
     System.out.println(p);
     //2.2
     Field f2=cla.getDeclaredField("age");
     f2.setAccessible(true);
     f2.set(p, 20);
     System.out.println(p);
     
     //3.通过反射调用运行时类的指定的方法
     Method m1=cla.getMethod("show");
     m1.invoke(p);
     
     Method m2=cla.getMethod("display", String.class);
     m2.invoke(p, "China");
    }    
    
    //不使用反射的情况下,创建一个对象,并调用其中的属性、方法    
    public void test1(){
       Person person=new Person();
       person.setName("LiMing");
       person.setAge(20);
       person.show();
       person.display("HK");
    }
}
public class Person {
     private String name;
     private int age;
     public Person(){
         super();
     }
     public Person(String name){
         super();
         this.name=name;
     }
     public Person(String name,int age){
         super();
         this.name=name;
         this.age=age;
     }
     
     public void setName(String name){
         this.name=name;
     }
     public String getName(){
         return name;
     }
     public void setAge(int age){
         this.age=age;
     }
     public int getAge(){
         return age;
     }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
    public void show(){
        System.out.println("我是一个人!");
    }
    public void display(String nation){
        System.out.println("我的国籍是:"+nation);
    }
}
java.lang.Class:是反射的源头
我们创建了一个类,通过编译(javac.exe)生成相应的.class文件。之后我们使用java.exe加载(JVM的类加载器)此.class文件,此.class文件加载到内存以后,就是一个运行时类,存在缓冲区,那么这个运行时类本身就是一个Class实例。
    1.一个运行时类只加载一次。
    2.有了Class类的实例以后,我们才可以进行如下的操作:
        1)创建对应的运行时类的对象
        2)获取对应的运行时类的完整结构(属性、方法、构造器、内部类、父类、所在的包、异常、注解...)
        3)调用对应的运行时类的指定的结构(属性、方法、构造器)
        4)反射的应用:动态代理
 
实例化Class类对象(四种方法):
    1.若已知具体的类,通过类的class属性获取,该方法 最为安全可靠,程序性能最高
                实例:Class clazz = String.class;
       2.已知某个类的实例,调用该实例的getClass()方法获取Class对象
                实例:Class clazz = “www.atguigu.com”.getClass();
       3.已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException
                实例:Class clazz = Class.forName(“java.lang.String”);
       4.通过类的加载器(类加载器是用来把类(class)装载进内存的)(了解)
                ClassLoader cl = this.getClass().getClassLoader();
                Class clazz4 = cl.loadClass(“类的全类名”);
public void test4() throws ClassNotFoundException{
        //调用运行时类本身的.class属性
        Class cla1=Person.class;
        System.out.println(cla1.getName());//返回com.atguigu.java.Person
        Class cla2=String.class;
        System.out.println(cla2.getName());//返回java.lang.String
        
        //通过运行时类的对象获取
        Person p=new Person();
        Class cla3=p.getClass();
        System.out.println(cla3.getName());//返回com.atguigu.java.Person
        
        //通过运行时类的静态方法forName获取
        Class cla4=Class.forName("com.atguigu.java.Person");
        System.out.println(cla4.getName());//返回com.atguigu.java.Person
    } 
创建类对象并获取类的完整结构:
         创建类的对象:调用Class对象的newInstance()方法
                   要求:1)类必须有一个无参数的构造器。
                     2)类的构造器的访问权限需要足够。
       //1.根据全类名获取对应的Class对象
       String name = “atguigu.java.Person";
       Class clazz = Class.forName(name);
       //2.调用指定参数结构的构造器,生成Constructor的实例
       Constructor con = clazz.getConstructor(String.class,Integer.class);
       //3.通过Constructor的实例创建对应类的对象,并初始化类属性
       Person p2 = (Person) con.newInstance("Peter",20);
       System.out.println(p2);
 
 
通过反射调用类中的指定方法、指定属性:
1.调用指定属性
先获取属性
public Field getField(String name) 返回此Class对象表示的类或接口的指定的public的Field。
public Field getDeclaredField(String name)返回此Class对象表示的类或接口的指定的Field。
在Field中:
public Object get(Object obj) 取得指定对象obj上此Field的属性内容
public void set(Object obj,Object value) 设置指定对象obj上此Field的属性内容
注:在类中属性都设置为private的前提下,在使用set()和get()方法时,首先要使用Field类中的setAccessible(true)方法将需要操作的属性设置为可以被外部访问。
public void setAccessible(true)访问私有属性时,让这个属性可见。
2.调用指定方法
通过反射,调用类中的方法,通过Method类完成。步骤:
    1).通过Class类的getMethod(String name,Class…parameterTypes)方法取得一个Method对象,并设置此方法操作时所需要的参数类型。
    2).之后使用Object invoke(Object obj, Object[] args)进行调用,并向方法中传递要设置的obj对象的参数信息。
    //调用运行时类中指定的属性
    public void test5() throws Exception{
        Class cla=Person.class;
        //1.获取指定的属性
        Field name=cla.getField("name");
        //2.创建运行时类的对象
        Person p=(Person)cla.newInstance();
        //3.将运行时类的指定的属性赋值
        name.set(p, "LiMing");
        System.out.println(p);
        
        Field age=cla.getDeclaredField("age");
        age.setAccessible(true);
        age.set(p, 20);
        System.out.println(p);
    }
    //调用运行时类中指定的方法
    public void test6() throws Exception{
        Class cla=Person.class;
        //获取运行时类中声明为public的指定的方法
        Method m1=cla.getMethod("show");
        Person p=(Person)cla.newInstance();
        //调用指定的方法
        Object returnVal=m1.invoke(p);
        
        //对于运行时类中静态方法的调用,无需创建运行时类的对象,直接使用类调用对象
        Method m2=cla.getMethod("info");
        m2.invoke(Person.class);
    }  

 

 posted on 2016-04-10 15:01  Marval  阅读(272)  评论(0编辑  收藏  举报