反射

一.反射的原理图

二.获取class对象<字节码文件对象>的方式

    1. Class.forName("全类名"):将字节码文件加载进内存,返回Class对象
        * 多用于配置文件,将类名定义在配置文件中。读取文件,加载类
    2. 类名.class:通过类名的属性class获取
        * 多用于参数的传递
    3. 对象.getClass():getClass()方法在Object类中定义着。
        * 多用于对象的获取字节码的方式

    * 结论:
        同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。

三.class对象的功能

  • 获取构造方法

  • 获取成员方法

  • 获取成员变量

三.(1)获取构造方法

获取构造方法们:
* Constructor<?>[] getConstructors()
* Constructor<T> getConstructor(类<?>... parameterTypes)

* Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
* Constructor<?>[] getDeclaredConstructors()

 //0.获取Person的Class对象
        Class<Person> personClass = Person.class;

        //1.获取带参的构造方法
        Constructor<Person> constructor = personClass.getConstructor(String.class, int.class);
        Person person = constructor.newInstance("张三", 23);
        System.out.println(person);

        System.out.println("=================================");

        //2.获取不带参的构造方法可以使用更简便的方法
        // 使用字节码文件对象,直接获取构造方法
        Person person1 = personClass.newInstance();
        System.out.println(person1);

注意事项:

1.不带Declared的方法,如:

* Constructor<?>[] getConstructors()
* Constructor<T> getConstructor(类<?>... parameterTypes)

     这两个方法只能获取被public修饰的构造方法.

2.带Declared的方法,如

* Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
* Constructor<?>[] getDeclaredConstructors()

这两个方法是可以获取被任何修饰符修饰的构造方法的

3.如果用构造方法来声明对象的话;

          带参的构造方法,要先用字节码文件对象获取构造方法,其中参数中要带上类型的字节码文件对象

                                     然后用获取到的构造方法来声明类的对象

         不带参的构造方法:可以直接用字节码文件对象,调用newInstance()来获取类的对象

三.(2) 获取成员方法

获取成员方法们:
   * Method[] getMethods()
   * Method getMethod(String name, 类<?>... parameterTypes)

   * Method[] getDeclaredMethods()
   * Method getDeclaredMethod(String name, 类<?>... parameterTypes)

//0.获取Person的字节码文件对象
        Class<Person> personClass = Person.class;
 //获取指定名称的不带参的方法
        Method eat_method = personClass.getMethod("eat");
        eat_method.invoke(new Person()); //传入类的对象  //此方式是直接声明Person类的对象
        eat_method.invoke(personClass.newInstance());  //此方式是通过字节码文件对象来创建Person类的对象


        //获取指定名称的带参的方法
        Method eat_method2 = personClass.getMethod("eat", String.class);
        eat_method2.invoke(new Person(),"饭");
        eat_method2.invoke(personClass.newInstance(),"香蕉");

        System.out.println("=================================================");

        Method[] methods = personClass.getMethods(); //会把Object中的方法都一并获取了
        for(Method method : methods){
            System.out.println(method);
            //获取方法名, 不是全类名来的
            System.out.println(method.getName());
        }

        //如果要使用不是被public修饰的方法的话
        //还是要调用setAccessible(true)方法来实现

        //获取类名(全类名)
        String className = personClass.getName();
        System.out.println(className);

注意事项:

1.不带Declared的方法,如:

* Method[] getMethods()
* Method getMethod(String name, 类<?>... parameterTypes)

     这两个方法只能获取被public修饰的构造方法.

2.带Declared的方法,如

* Method[] getDeclaredMethods()
* Method getDeclaredMethod(String name, 类<?>... parameterTypes)

这两个方法是可以获取被任何修饰符修饰的成员方法的

3.调用获取的方法是使用 invoke方法的,方法中一定要传入类的对象

                获取类的对象有两种方法:

                             (1) 用实体类直接new出来

                             (2) 用字节码文件对象,获取构造方法,然后通过调用newInstance()来获取类的对象

            

  对于为啥在调用方法的时候,要传入类的对象的个人看法:

          字节码文件中的methods数组中包含了类中所有的方法,在我们通过字节码文件对象获取了某一个方法之后,我们想要调用此方法,但是尴尬的是,我们并不知道这个方法是属于哪一个对象,不知道是p1对象的 还是p2对象的 抑或是 p3对象的,所以我们在调用方法的时候,必须传入实体类对象作为参数

4.如果调用获取的方法中,是带参数的,那么调用方法的时候,参数是加在实体类对象之后的

三.(3)获取成员变量

获取成员变量们
* Field[] getFields()             
* Field getField(String name)

* Field[] getDeclaredFields()    
* Field getDeclaredField(String name)

 //0.获取字节码文件对象
        Class<Person> personClass = Person.class;

 //1.Field[] getFields()获取所有public修饰的成员变量
        Field[] fields = personClass.getFields();
        for(Field field : fields){
            System.out.println(field);
        }

        System.out.println("=====================================");

        //2.Field getField(String name)
        Field a = personClass.getField("a"); //只能获取被public修饰的属性

        // 获取成员变量a的值
        Person person = new Person();
        Object value = a.get(person);
        System.out.println(value);
        //设置a的值
        a.set(person,"张三");
        System.out.println(person);
        System.out.println("======================================");

        //Field[] getDeclaredFields():获取所有的成员变量,不考虑修饰符
        Field[] declaredFields = personClass.getDeclaredFields();
        for(Field declaredField : declaredFields){
            System.out.println(declaredField);
        }

        //Field getDeclaredField(String name)  获取指定的成员变量,并且不考虑修饰符
        Field d = personClass.getDeclaredField("d");
        //忽略访问权限修饰福的安全检查
        d.setAccessible(true); //暴力反射
        Object value2 = d.get(person);
        System.out.println(value2);

注意事项:

1.不带Declared的方法,如:

 Field[] getFields()             
* Field getField(String name)

     这两个方法只能获取被public修饰的成员变量.

2.带Declared的方法,如

* Field[] getDeclaredFields()    
* Field getDeclaredField(Strin g name)

这两个方法是可以获取被任何修饰符修饰的成员变量的

3.对于成员变量来说,操作成员变量只有两种可能: 

     (1)获取成员变量的值:

            使用get方法,其中get方法中,要传入实体类的对象,因为要知道获取哪一个对象中的成员方法

    (2)设置成员变量的值

          使用set方法,其中,第一个参数一定是传入实体类的对象,因为要知道给哪一个成员变量赋值,后面的参数是所赋的值

4.如果要获取不是被public所修饰的成员变量的值或者给不是被public所修饰的成员变量赋值',一定要忽略访问权限修饰符的安全检查

d.setAccessible(true); //暴力反射

 此处,d为获取的成员变量,要先暴力反射,才能做后续的操作.

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值