- 什么是反射:正常使用一个类,可以直接对他实例化(new),之后直接操作这个对象实例,而反射中,我们使用JDK提供的API对不特定的类进行实例化——<1>只有在运行时才知道要操作的类(需要对得到的不确定类进行强制类型转换);<2>能在运行时完整地获取类的构造,并调用其方法
- Class中有什么
编译器将我们编写的java文件和Class.java一起编译成.class文件。将类的元数据信息放在.class文件末尾,虚拟机中对一个类的定义只会有一份,如果没有则先读出class文件,再进行new操作(实例化)
Class中包括了Field、Method和Constructor。 - 反射怎么用
获取一个类的class的三种方法:
- Example.class
- example.getClass()
- Class.forName(包名+类名)
获取对象之后:
<1>getConstructors()、getConstructor(参数的class...)
<2>getMethods()、getMethod()只能获取类与分类的可见方法
<3>getDeclaredMethods和getDeclaredMethod能获得所有方法,包括私有的,但只有当前类的,父类不可见
<4>用Method类中的invoke()可对方法进行调用
<5>使用私有的域和方法也需要先setAccessible
反射在运行时才去生成、加载、调用这个class文件,因此效率比正常的new低
代理模式那些事
定义
给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用
目的
- 通过引入代理对象来间接访问目标对象,防止直接访问带来不必要的复杂性
- 通过代理对象对原有的业务增加,但都包含同样的接口
静态代理,违反开闭原则,扩展能力差,可维护性差
动态代理,在使用时再创建代理类和实例,要用反射机制,效率比静态低,使用场景受限(Java单继承,只对接口代理)
<1>Proxy 主体(产生动态代理对象)
<2>InvocationHandler 事务处理
代理类实现Proxy.newProxyInstance,通过getProxyInstance给外部类调用,代理实现InvocationHandler,类似于拦截。
如果打印出生成的字节数组到.class文件并反编译,可以看到动态代理生成的类,以Proxy为父类,实现了需要代理的接口(Proxy+InvocationHandler)
Retrofit
它是网络请求的适配器,可以吧Java的接口翻译成http请求,通过okhttp去发送请求
步骤是:
- 创建一个接口文件,通过注解声明需要用到的请求的信息;
- 使用Retrofit的构造器创建一个实例;
- 用Retrofit实例的create方法创建出了接口的示例;
- 在业务中调用接口文件中的方法进行请求。
其中第三步就使用了动态代理创建了接口的代理类与实例,完成了其中的事务处理(InvocationHandler)。
建议
可以通过静态代理的实现和动态代理的实现进行实操了解
答疑
- 静态代理使用的场景很少(除非使用的场景很少且不考虑再扩展),绝大部分都是用的动态代理
- 对newProxyInstance传入的interfaces数组进行了clone,是因为Java是传值引用,通过方法传入的interfaces变量只是它的引用,通过clone这个变量并用final修饰它,避免内部修改对外部数组的影响
ps.原来的标题
- 什么是反射?
- 从代理模式到静态代理;
- 从静态代理到动态代理;
- 从源码底层深入解密动态代理;
- Retrofit是如何是动态代理的?