40.反射

java反射机制是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法。
对于任意一个对象,都能够调用它的任意一个方法和属性。这种动态获取的信息及动态调用对象的方法的功能称为java的反射机制。

要想对字节码文件进行解剖,必须要有字节码文件对象。
如何获取字节码文件对象呢?

 

先建立Person对象

public class Person {

    private int age;
    private String name;
    public Person(){
        System.out.println("person run");
    }
    
    public Person(String name,int age){
        super();
        this.age=age;
        this.name=name;
        
        System.out.println("person param run"+this.name+":"+this.age);
    }
    
    public void show(){
        System.out.println(name+"...show run..."+age);
    }
    
    private void privateMethod(){
        System.out.println("method run");
    }
    
    public void paramMethod(String str,int num){
        System.out.println("paramMethod run......"+str+":"+num);
    }
    
    public static void staticMethod(){
        System.out.println("static method run");
    }
}

 

 

public class ReflectDemo_01 {

    public static void main(String[] args) throws ClassNotFoundException {
        // TODO Auto-generated method stub

        //getClassObj_1();
        
        //getClassObj_2();
        
        getClassObj_3();
        
    }
    
    /*
     * 获取字节码对象的方式:
     * 1.Object类中的getClass()方法。
     * 想要用这种方式,必须要明确具体的类,并创建对象。麻烦
     */
    public static void getClassObj_1(){
        Person p=new Person();
        Class clazz=p.getClass();

        Person p1=new Person();
        Class clazz1=p1.getClass();
        
        System.out.println(clazz==clazz1);//true  依赖同一个class类对象完成的
    }
    
    /*
     *方式二:
     *2.任何数据类型都具备一个静态的属性.class来获取其对应的Class对象
     *相对简单,但是还是要明确用到类中的静态成员class。还是不够扩展。
     */
    public static void getClassObj_2(){
        Class clazz=Person.class;
        Class clazz1=Person.class;
        
        System.out.println(clazz==clazz1); //true
    }
    
    /*
     * 方式三:
     * 3.只要通过给定的类的字符串名称就可以获取该类,更为扩展。可以用Class类中的方法完成。该方法就是forName
     * 这种方式 只要有名称即可,更为方便,扩展性更强
     */
    public static void getClassObj_3() throws ClassNotFoundException{
        String className="day26.Person"; //带包名
        Class clazz=Class.forName(className);
        System.out.println(clazz);
    }
}

 

构造器

public class ReflectDemo_02 {

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
        // TODO Auto-generated method stub

        //createNewObj();
        createNewObj_1();
        
    }
    
    public static void createNewObj() throws ClassNotFoundException, InstantiationException, IllegalAccessException{
        
        //早期:new的时候先根据被new的类的名称找寻该类的字节码文件,加载进内存,并且创建该字节码文件对象,接着创建该字节文件对应的Person对象
        //Person p=new Person();  //person run
        
        //现在:
        String name="day26.Person";
        //找寻该名称类文件,加载进内存,并产生Class对象
        Class clazz=Class.forName(name);
        //如何产生该类的对象呢?
        Object obj=clazz.newInstance();
        
    }

    public static void createNewObj_1() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
        //Person p=new Person("zhangsan",22);
        
        
        /*
         * 当要获取指定名称对应的类中所写的对象时,而该对象初始化不使用空参数构造函数时,该怎么办?
         * 既然是通过指定的构造函数进行对象的初始化,所以应该先获取到该构造函数。通过字节码文件对象即可完成。
         * 该方法是:getConstructor(paramterTypes)
         */
        String name="day26.Person";
        Class clazz=Class.forName(name);
        //获取到指定的构造函数对象
        Constructor cons=clazz.getConstructor(String.class,int.class); //任何数据类型都可以被class描述
        
        //通过该构造器的newInstance方法进行对象的初始化
        Object obj=cons.newInstance("小明",29); 
    }
}

 

属性

public class ReflectDemo_03 {

    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub

        getFieldDemo();
    }
    
    /*
     * 获取字节码文件中的字段
     */
    public static void getFieldDemo() throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException{
        
        Class clazz=Class.forName("day26.Person");
        
        Object obj=clazz.newInstance();
        
        Field field=clazz.getDeclaredField("age"); //只能获取本类,但包含私有
        
        //对私有字段的访问,取消权限检查。暴力访问
        field.setAccessible(true);
        
        field.set(obj, 39);
        
        //返回指定对象上此 Field 表示的字段的值。
        Object o=field.get(obj);
        
        System.out.println(o);
    }
}

 

方法

public class ReflectDemo_04 {

    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub

        //getMethodDemo();
        
        getMethodDemo_1();
        
        //getMethodDemo_2();
         
    }

    /*
     * 获取指定Class中的所有公共函数
     */
    public static void getMethodDemo() throws Exception{
        
        Class clazz=Class.forName("day26.Person");
        
        Method[] methods=clazz.getMethods(); //获取的都是共有的方法
        methods=clazz.getDeclaredMethods(); //只获取本类中所有方法,包括私有的
        
        for(Method m:methods){
            System.out.println(m);
        }
    }
    
    /*
     * 调取无参方法
     */
    public static void getMethodDemo_1() throws Exception{
        
        Class clazz=Class.forName("day26.Person");
        
        Method method=clazz.getMethod("show", null); //获取空参数一般方法
        
        //给对象赋值
        Constructor cons=clazz.getConstructor(String.class,int.class);
        Object obj=cons.newInstance("小明",37);
        
        //调用方法
        method.invoke(obj, null);
    }
    
    /*
     * 调取有参方法
     */
    public static void getMethodDemo_2() throws Exception{
        
        Class clazz=Class.forName("day26.Person");
        
        Method method=clazz.getMethod("paramMethod", String.class,int.class);//获取有参构造器
        
        Object obj=clazz.newInstance();
        
        method.invoke(obj,"张三",29);
        
    }
}

 

posted @ 2018-02-02 15:18  一日看尽长安花cxjj  阅读(111)  评论(0)    收藏  举报