Java反射(一)

1.

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

动态获取类中的信息就是Java的反射机制。可以理解为对类的解剖。

2.

反射大大的提高了程序的扩展性。
反射是程序为外部提供了接口和配置文件,通过对接口的实现和对配置文件的配置,程序通过反射会自动加载实现了接口的类,从而读取类中内容,实现程序的扩展。

3.

通过一个类的字节码文件获得该类的属性和方法。
通过class文件对象去使用该文件中的成员变量,构造方法,成员对象
要想这样使用,必须先得到class文件的对象,其实就是的到class类的对象
    class类包括:
        成员变量
        构造方法
        成员方法
获取class文件对象的方式
    A:object类的getClass()
        --Person p = new Person();
          Class c = p.getClass();
    B: 数据类型的静态属性class
        --Class c = Person.class;或
        --Class c = int.class;或
        --Class c = String.class;
    C: class类中的静态方法
    --public static Class forName(String className)
    --括号内的部分写的是类的带包全路径,即使是在同一个包下也要写全路径,否则会报找不到异常
    --Class c = Class.forName("com.qfxa.Person");

一般我们使用哪一种呢?
A:自己玩 可以任选一种,第二种比较方便
B: 开发 选第三种
因为第三种是一个字符串,而不是一个具体的类名。这样我们就可以把这样的字符串配置到配置文件中。

4.通过反射获取构造方法并使用

通过反射获取构造方法并使用
1)获取字节码文件对象
    Class c = Class.forName("com.qfxa.Person");


2)获取构造方法
            public Constructor[] getConstructors(); --所有public的构造方法
            --返回一个包含某些Constructor对象的数组,这些对象反映此Class对象所表示的类的所有**公共**构造方法。
            Constructor[] cons = c.getConstructors();
            //遍历获取的构造方法
            for(Constructor con : cons){
                System.out.println(con);
            }

2)想获取所有的构造方法,可以用
        public Constructor[] getDeclaredConstructors(); 
        这个方法,返回Constructor对象的一个数组,这些对象反映此Class对象表示的类声明的**所有**构造方法。

        --Constructor[] cons = c.getDeclaredConstructors();

  想获取单个构造方法,可以用(但是只能获得public修饰的构造方法)
        public Constructor getConstructor(Class...parameterTypes)
        --...代表可变参数,有参数也行没有参数也行
        --因为构造方法的参数可能有很多个也可能没有,所以用可变参数来代替所有的参数。
        --参数表示的是:你要获取的构造方法的构造参数个数及数据类型的class字节码文件对象。
        --Constructor con = c.getConstructor(); //返回的是空参构造方法对象。
        --Constructor con = c.getConstructor(String.class,int.class,String.class);//返回的是例子中的三参构造方法对象。

    通过反射获取私有的构造方法
        public Constructor getDeclaredConstructor(Class...parameterTypes)

        --Constructor con = c.getDeclaredConstructor(String.class); 
        --这样会获得私有的构造方法,但是不能访问,因为私有的构造方法在外界不能访问。
        --con.setAccessible(true);  --通过这样设置,值为true代表反射的对象在使用时应取消java语言访问检查,这时候就可以访问私有构造方法了。

3)根据获取的构造方法创建新实例
        --用的方法:public T newInstance(Object... initargs)
        --使用此Constructor对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
        --T代表泛型
        --Object obj = con.newInstance();   --obj表示的是Person类的对象
        --Object obj = con.newInstance("tom",12,"haha");        --表示是通过三参构造方法获得的新实例。

5.通过反射获取成员变量并使用

通过反射获取成员变量并使用
    --获取所有成员
    getFields.getDeclaredFields
    --获取单个成员
    getFields.getDeclaredField
    --修改成员的值
    set(Object obj,Object value)    //将指定对象上此Field对象表示的字段设置成指定的新值。
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

//通过反射获取成员变量并使用
public class ReflectDmeo {
    public static void main(String[] args) throws Exception {

        //获取字节码文件对象
        Class c = Class.forName("com.qfxa.Person");

        //获取所有的public成员变量
        Field[] fields1 = c.getFields();

        for(Field field : fields1){
            System.out.println(field);
        }

        //获取所有的成员变量
        Field[] fields =  c.getDeclaredFields();

        for(Field f : fields){
            System.out.println(f);
        }

        //获取单个成员变量
        //获取address并对其赋值
        /**
         * Person p = new Person();
         * p.address = "Beijing";
         * System.out.println(p);
         */
        Field addressField = c.getField("address");


        //通过无参构造创建对象
        Constructor constructor = c.getConstructor();
        Object object = constructor.newInstance();
        //System.out.println(object);

        //public void set(Object obj,Object value)
        //将指定对象变量上此Field对象表示的字段设置为指定的新值。
        addressField.set(object, "beijing");    //给object对象的addressField字段设置值为北京


        /**
         * 需求:通过反射获取成员变量并使用
         * 1.获取类的字节码文件对象
         *      --Class c = Class.forName("com.qfxa.Person");
         * 2.获取单个成员变量address
         *      --Field addressField = c.getField("address");
         * 3.通过无参构造创建对象(原因是给成员变量设置新值时需要指定是哪个对象,所以需要创建一个对象)
         *      --Constructor constructor = c.getConstructor();
         *      --Object object = constructor.newInstance();
         * 4.将指定对象变量上此Field对象表示的字段设置为指定的新值
         *      --addressField.set(object, "beijing"); 
         */


        //获取成员变量name并对其赋值

        //Field nameField = c.getField("name"); --会报下面错误
        //Exception in thread "main" java.lang.NoSuchFieldException: name
        //报错是因为name这个成员变量是私有的,所以要用另一个方法getDeclaredField
        Field nameField = c.getDeclaredField("name");
        //Exception in thread "main" java.lang.IllegalAccessException: Class com.qfxa03.ReflectDmeo can not access a member of class com.qfxa.Person with modifiers "private"
        //还报错是因为获取的成员变量name是私有的,不能访问,所以要设置setAccessible为true
        nameField.setAccessible(true);
        //修改成员变量name的值
        nameField.set(object, "linqingxia");
        System.out.println(object);


        //获取成员变量age并赋值
        //管他的,直接用getDeclaredField方法调用,以便于能获得私有的成员变量
        Field ageField = c.getDeclaredField("age");
        //同样,管他的,直接设置了取消java的访问检查,以便于能对私有成员变量进行访问
        ageField.setAccessible(true);
        //设置新建的object对象的age为指定值
        ageField.set(object, 10);
        System.out.println(object);
    }
}

6.通过反射获取成员方法并使用

获取所有方法
    --getMethods
    --getDeclaredMethods
获取单个方法
    --getMethod
    --getDeclaredMethod
暴力访问
    --method.setAccessible(true);
package com.qfxa04;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class ReflectDemo {
    public static void main(String[] args) throws Exception{

        //获取字节码文件
        Class c = Class.forName("com.qfxa.Person");

        //获取所有的方法
            --Method[] methods = c.getMethods();    //--获取自己的和父亲的public方法
            --Method[] methods = c.getDeclaredMethods();    //--获取自己的所有方法不包括父亲的


        //获取单个方法并使用
            /**
             * Person p = new Person();
             * p.show();
             */

        //获得构造方法
        Constructor con = c.getConstructor();

        //根据构造方法创建对象
        Object object = con.newInstance();

        //要拿到public void show()方法
        //获取单个方法需要用到这个方法
            --public Method getMethod(String name,Class...ParameterTypes)
            --第一个参数表示的参数名,第二个参数表示的是方法的参数的class类型

        Method m1 = c.getMethod("show");

        //public Object invoke(Object obj,Object... args)
        --返回的是object接收,第一个参数表示对象是谁,第二个参数表示调用该方法的参数
        m1.invoke(object);  //其本质是调用objec的m1方法
        --因为show 方法没有返回值也没有参数,所以这样写。


        //获得public void method(String s)这个方法
        Method m2 = c.getMethod("method", String.class);
        m2.invoke(object, "hahaha");

        //获取public String getString(String s,int i)这个方法
        Method m3 = c.getMethod("getString", String.class, int.class);
        Object objString = m3.invoke(object, "haha", 10);或者
        String string = (String)m3.invoke(object, "hahah", 10); 
        --当你知道返回的具体是什么类型的时候可以直接强制转成对应类型,否则用object接收,因为object可以接收所有类型
        System.out.println(objString);
        System.out.println(string);


        //获得private void function()这个方法
        Method m4 = c.getDeclaredMethod("function");
        m4.setAccessible(true);
        m4.invoke(object);

    }
}

你可能感兴趣的:(java反射)