泰涨知识 | Java反射深入浅出

2022-09-02 18:51:51 阅读量:


\
 
本文,我们将带领大家从Java反射基础了解到JDK动态代理源代码解析反射的作用,深入浅出,真实体会Java反射的妙用。

我们从以下6个方面讲解Java反射:
1. 反射的概念
2. 反射的三个阶段
3. Class对象
4. 反射与代理模式
5. JDK动态代理源码解析
6. 反射的其他妙用

   反射的概念   

将类的各个组成部分封装成其他对象,这就是反射机制
反射就是框架的实现机制和实现途径,所谓框架就是软件的半成品。在框架的基础上进行软件开>发,提高效率,简化代码。
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
使用前提:
必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码文件)
 

    反射的三个阶段   

要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象。
 
\ 
 
使用反射的优缺点:
优点:
1.可以在程序运行过程中,操作这些对象
2.可以解耦,提高程序的可扩展性
缺点:
1.提高了代码的复杂度,在复杂项目中写放射反而更复杂,慎重使用
 

   Class对象   

获取Class对象的三种方法:根据加载时间节点选择

1.Source源代码阶段:
Class.forName(“全类名”);
将字节码文件加载进内存,返回Class对象
多用于配置文件,将类名定义在配置文件中。读取文件,加载类

2.Class类对象阶段:
类名.class;
通过类的属性class获取Class对象
参数的传递中使用
3.RunTime运行时阶段:
对象.getClass();方法获取Class对象
该方法是定义在Object类中的
用内存中的对象,反取得Class类对象
至于Class对象的组成常用api本文就不再赘述,可以参考jdkapi文旦,但一定注意jdk版本参考,1.8~11一个版本,11+一个版本参考
 
列举一个案例:
JDK9以上模块不能使用反射去访问非公有的成员/成员方法以及构造方法,除非模块标识为opens去允许反射访问。
虽然我们设置了字段field.setAccessible(true)但是还是无法进行赋值,这个时候就需要改变jvm参数。
 \


   反射与代理模式   

说到代理模式,那一定会想到Spring框架中的AOP处理,aop是经典的代理模式的使用机制。

那接下来就来讲讲代理模式,因为代理模式实现中有很多反射的影子
从AOP来讲,我们常说的使用到了JDK动态代理与CGLIB代理,他们都是动态代理的实现模式
那要认识代理模式我们先了解什么是静态代理认识
 

静态代理

静态代理中,我们对目标对象的每个方法的增强都是手动完成的,非常不灵活且麻烦。实际应用场景非常非常少,日常开发几乎看不到使用静态代理的场景。
从 JVM 层面来说, 静态代理在编译时就将接口、实现类、代理类这些都变成了一个个实际的 class 文件。

代码案例:

1.定义业务接口
\

2.定义业务接口实现类
\

3.代理类
\

4.创建代理类
\

动态代理

相比于静态代理来说,动态代理更加灵活。我们不需要针对每个目标类都单独创建一个代理类,并且也不需要我们必须实现接口,我们可以直接代理实现类( CGLIB 动态代理机制)。

 

   JDK动态代理   

Java 动态代理机制中 InvocationHandler 接口和 Proxy 类是核心
Proxy 类中使用频率最高的方法是:newProxyInstance() ,这个方法主要用来生成一个代理对象案例代码;

1.定义业务接口
\

2.定义业务接口实现类
\

3.代理类

\

4.创建代理对象的工程类
\那JDK动态代理中哪些是使用反射实现的呢?

(1)我们从Proxy.newProxyInstance方法入手来看看
 \\

(2)在进入获取代理类的字节码文件对象,getProxyClass0方法看看
\那问题就来了,缓存没有的话,代理对象的字节码对象是如何生产的,我们就要了解Proxy的一个相关类叫ProxyGenerator.generateProxyClass

(3)ProxyGenerator.generateProxyClass源码
 \\

(4)我们通过案例可以看看生成的代理类的字节码文件内容:
\\\\\\

总结:
通过上述案例我们看出,其实在jdk动态代理过程中运用到了类加载器,其实动态代理就是模拟生成出一个类加载器能加载的.class文件的io字节流让类加载器加载,所以只要符合要求的不一定真实输出文件也能创建Class对象,也就能生成对象。
 
同时我们也发现,JDK代理实际的运行效果就是通过目标类的接口实现一个相同的子类替代目标类的行为,只是创建代理对象的过程没有实际可见效果,所以动态代理实际原理也是这样的。