关注△mikechen的互联网架构△,10年+BAT架构经验倾囊相授
大家好,我是 mikechen | 陈睿 。
反射非常强大和有用,现在市面上绝大部分框架(spring、mybatis、rocketmq等等)中都有反射的影子,在框架设计中,反射机制占有举足轻重的作用。
所以,在你Java进阶的道路上,你需要掌握好反射@mikechen
怎么才能学好反射,我们需要弄懂以下几个问题:
- 反射是什么?
- 反射有什么用?
- 反射的实现原理?
- 怎么用反射?
下面,我就针对上述疑问,逐一进行讲解@mikechen
反射是什么?
反射是java语言的一个特性,它允程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。
反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意方法和属性,这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
一句话总结:反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。
为什么要用反射?
Java Reflection功能非常强大,并且非常有用,比如:
- 获取任意类的名称、package信息、所有属性、方法、注解、类型、类加载器等
- 获取任意对象的属性,并且能改变对象的属性
- 调用任意对象的方法
- 判断任意一个对象所属的类
- 实例化任意一个类的对象
- 通过反射我们可以实现动态装配,降低代码的耦合度,动态代理等。
怎么使用反射?
一般情况下我们通过反射创建类对象主要有两种方式:
- 通过 Class 对象的 newInstance() 方法
- 通过 Constructor 对象的 newInstance() 方法
第一种:通过 Class 对象的 newInstance() 方法。
Class clz = Class.forName("com.mikechen.reflection.JiaGou");
JiaGou jg= (JiaGou)clz.newInstance();
第二种:通过 Constructor 对象的 newInstance() 方法
Class clz = Class.forName("com.mikechen.reflection.JiaGou");
Constructor constructor = clz.getConstructor();
JiaGou jg= (JiaGou)constructor.newInstance();
通过 Constructor 对象创建类对象可以选择特定构造方法,而通过 Class 对象则只能使用默认的无参数构造方法,下面的代码就调用了一个有参数的构造方法进行了类对象的初始化。
Class clz = Class.forName("com.mikechen.reflection.JiaGou");
Constructor constructor = clz.getConstructor(String.class);
JiaGou jg= (JiaGou)constructor.newInstance("mikechen的互联网架构");
接下来,我们就可以通过具体的API,调用获取到详细的属性或者方法等详细了。
1、获取类的成员变量的信息
//mikechen的互联网架构
Field[] fields = cls.getDeclaredFields();
更加详细成员变量获取参考如下:
2、获得类方法
//mikechen的互联网架构
Method[] methods = cls.getDeclaredMethods();
更加详细方法获取参考如下:
3、获得构造函数
//mikechen的互联网架构
Constructor[] constructors = cls.getDeclaredConstructors();
更加详细构造函数获取参考如下:
这样,我们通过反射,就可以做在运行时获取类的完整构造,并获得类信息了。
通过以上一个小案例了解了反射的使用,但如果你想对反射掌握得更好,还需深入理解反射背后的底层实现原理。
反射工作原理?
调用反射的总体流程如下:
1、当我们编写完一个Java项目之后,每个java文件都会被编译成一个.class文件。
2、这些class文件在程序运行时会被ClassLoader加载到JVM中,当一个类被加载以后,JVM就会在内存中自动产生一个Class对象。
3、通过Class对象获取Field/Method/Construcor
我们一般平时是通过new的形式创建对象实际上就是通过这些Class来创建的,只不过这个class文件是编译的时候就生成的,程序相当于写死了给jvm去跑。
反射是什么呢?当我们的程序在运行时,需要动态的加载一些类这些类可能之前用不到所以不用加载到jvm,而是在运行时根据需要才加载。
原来使用new的时候,需要明确的指定类名,这个时候属于硬编码实现,而在使用反射的时候,可以只传入类名参数,就可以生成对象,降低了耦合性,使得程序更具灵活性。
反射的应用场景
Spring 框架的 IOC(动态加载管理 Bean),Spring通过配置文件配置各种各样的bean,你需要用到哪些bean就配哪些,spring容器就会根据你的需求去动态加载,你的程序就能健壮地运行。
还有Spring AOP(动态代理)功能都和反射有关系。
Spring默认使用JDK的动态代理实现AOP,类如果实现了接口,Spring就会使用这种方式实现动态代理。
生成的代理类实现了原来那个类的所有接口,并对接口的方法进行了代理,我们通过代理对象调用这些方法时,底层将通过反射,调用我们实现的invoke方法。
public class Main { public static void main(String[] args) {
//获取InvocationHandler对象 在构造方法中注入目标对象
InvocationHandler handler = new JdkProxySubject(new RealSubject());
//获取代理类对象
Subject proxySubject = (Subject)Proxy.newProxyInstance(Main.class.getClassLoader(), new Class[]{Subject.class}, handler);
//调用目标方法
proxySubject.request(); proxySubject.response();
}
除此之外,还有很多框架都会用到反射机制,例如 MyBatis、Dubbo、RocketMQ 等等。
以上,是 Java 反射的详细解析,欢迎评论区留言交流或拓展。
我是 mikechen | 陈睿 ,关注【mikechen的互联网架构】,10年+BAT架构技术倾囊相授。
本文已同步我的技术博客 www.mikechen.cc,更新至我原创的《30W+字大厂架构技术合集》中。