反射学习小记

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Mackyhuang/article/details/82431819

反射

@author:MackyHuang

什么是反射

  • 反射是JAVA API, 是Java提供的现成的类,接受API提供的内容
  • 是Java提供的动态执行机制,动态加载类,动态创建对象,动态访问属性,动态调用方法

静态和动态

  • 静态:事先约定好的规则,执行期间按照固定的规则执行
  • 动态:事先没有约定规则,在执行期间动态确定执行规则

动态加载类

Java提供了动态加载类的API

        Class cls = Class.forName("")

引号里面放的是类名

  • 一个类,被编译成.class文件,类加载器读取后存在于方法区中,java反射机制分析方法区中的字节码文件,输入className后,在堆中的Class去方法中找到相应的类的代码(类的属性和方法都在其中),然后在栈中创建引用,指向Class,这样就获得了一个cls->Class>具体类的过程

        Class cls = Class.forName(className);
        Object object = cls.newInstance();
    

这里通过newInstance()方法获取这个对象的实例,这里需要这个类提供无参构造器

com.cls.Test@74a14482
这个@后面的数字和地址有关系,但是绝对不是地址!

动态获取类的方法信息

            Method[] methods = cls.getDeclaredMethods();
            for (Method method : methods)
            {
                System.out.println(method);
            }

通过getDeclaredMethods()来获取方法信息,从方法区中抓取信息 ,返回的是一个Method[]数组,数组中是这样的字符串public int com.cls.Test.name2()

  • 这里Method还有一些方法来获取方法信息的局部信息,比如获取方法名之类的

动态执行方法

        method.invoke(对应的类的对象,参数1, 参数2);

因为在函数运行的时候,有一个隐藏参数就是this,在这里就相当于这个this,需要传入的参数也就是这个类的对象,然后接着输入参数,这样可以运行类的非静态方法,invoke有返回值,返回的是方法返回的值

invoke执行私有方法

        Class[] types = {String.class, int.class};
        Method method = cls.getDeclaredMethod("name3", types);
        method.setAccessible(true);

通过类型列表和getDeclaredMethod方法获取一个方法,
正常情况下,invoke无法访问私有方法,如果method获得打开访问权限,将setAccessible设置为true,就可以设置其访问私有属性,不过这样会破坏封装性(必要的时候再用)

反射的用途

  • eclipse 中解析类的结构使用了反射
  • Junit识别被测试方法使用了反射
    Junit3利用反射查找test开头的方法
    Junit4利用反射解析@Test查找测试方法
  • Spring管理Bean对象,注入Bean属性使用了反射
  • 注解的解析使用了反射
    利用反射API支持注解
  • 强行执行私有方法,访问私有属性

反射自己写一个注解

            String className = "";
            System.out.println("请输入类名");
            Scanner input = new Scanner(System.in);
            className = input.nextLine();
            Class cls = Class.forName(className);
            Object object = cls.newInstance();
            Method[] methods = cls.getDeclaredMethods();
            for (Method method : methods)
            {
                Demoo demoo = method.getAnnotation(Demoo.class);
                System.out.println(method + "  " + demoo);

            }

            @Retention(RetentionPolicy.RUNTIME)
            public @interface Demoo
            {

            }

以为这样就可以抓取到注解了吗,大错特错!
java文件被编译成class文件的时候,注解会被自动擦除,这是注解的默认在源文件中存在,就像这样:

            @Retention(RetentionPolicy.SOURCE)

需要修改为:

            @Retention(RetentionPolicy.CLASS)

不过这个时候,class进入代码区,注解还是没了,这个时候就需要:

            @Retention(RetentionPolicy.RUNTIME)

猜你喜欢

转载自blog.csdn.net/Mackyhuang/article/details/82431819