参考
b站 韩顺平
为什么用反射
反射可以根据一个方法名调用需要的方法,也可以直接跨权限访问
但是反射属于动态加载,运行时才耗时加载,会慢很多
静态与动态加载
静态加载就是编译字节码时一次性将字节码中所有类都给加载了
常见如new 对象
而动态加载是解释字节码,每次到用到的地方才会开始加载这个类
动态加载一般是反射
而我们知道,类加载时会优先检查父类和成员类的加载情况,这些类的加载失败往往也会导致异常
动态加载的坏处是感觉慢,其实大家时间差不多,但因为它在运行时才开始加载类,所以响应较慢;好处是灵活,因为它不会在编译时加载从而检验类的正确性,只有在运行到需要加载该类的地方才可能报错
原理
类加载的第一步时,是通过类的全限定名找到合适的类加载器类被类加载器加载后都会在堆中生成Class对象,其中存放着构造器,成员方法,成员变量,注解,泛型,形参等,而这些属性都以对象形式在堆中存放。
而反射就是直接调用这些对象
与此同时,所有对象的生成都是由Class对象完成,并且在对象头记录了Class对象的位置,如果我们要反射调用某个方法,可以通过对象获得类对象,然后获得其Method对象,然后调用它
基本四大类的关系
Class
获取方法
1 使用Class.forName(全限定名)尝试加载,如果有则返回,没有则自行选择类加载器加载并获得类对象
2 调用某类加载器加载并获得类对象,如classLoader1.loadClass(全限定名),如果有直接返回,没有才加载
3 类调用.class直接获得类对象
如int.class,test.class,需要注意的是基本类型包装类是.TYPE的,如Integer.TYPE
4 对象调用getClass()获得类对象
API
getMethod,获得指定public方法
getMethods,获得类和超类超接口所有public
getDeclaredMethods,获得本类和超类所有权限的方法
Constructor和Field大同小异
值得注意的是
1 getDeclaredConstructor只获得本类所有权限构造方法
2 所有API指定形参时都是使用类对应的Class对象
拥有Class对象的类
注解,枚举,类(包括外部类和各种内部类),接口,基本类型,数组(无论几维),void
Method
通过Method.invoke(对象)调用方法
值得注意的是
1 静态方法可以通过Method.invoke(null)获得
2 如果需要调用私有方法,需要使用setAccessible(true)去掉访问权限检查,这也可以提高调用速度
Field大同小异
一个类的划分
每个类在堆中都有一个Class对象,这个对象是个数据结构,指向数据存放的位置,数据大部分存放在元空间,元空间是一块JVM之外的内存,存放着类信息,方法信息,属性信息,静态变量,小部分存放在堆字符串常量池,这存放着各种常量