今天突然被问到一个问题,反射机制的作用是什么?一阵思索....发现说不清楚个所以然,于是想整理一下这个点的知识。
首先我是去翻了各位大佬的博客,然后我发现一个问题,那就是他们的博客都是在讲反射机制的用法,常用的方法,可以怎么用,等等....对新学的人极其不友好,本来就感觉反射已经够抽象了,看了一通常用方法后,好像知道怎么用了,但是一问用来干嘛,估计就和我之前的状态差不多了。。。。。所以这里记录一下个人对反射机制使用情况的理解,并不赘述(搬运)JDK里面的玩意儿,如果对常规用法都不了解的,可以先看这篇博客再回来继续阅读。https://zhuanlan.zhihu.com/p/117212406
java反射机制:
在运行过程中,对于任何一个类,都能够知道其所有的属性和方法,对于任意一个对象,都能够调用其属性和方法。这种能够动态的获取和调用对象方法的功能,就是JAVA的反射机制。
为了便于引入和理解后面我要说的,大家先来看一个简单的小东西:
当我们 “正向” 创建对象时
ArryList list = new ArrayList();
list.add("reflection");
...
当我们使用 “反向”(反射) 创建对象时
Class clz = Class.forName("java.util.ArrayList");
Method method_ add.clz.getMethod(" add",object.class)
Constructor constructor = c1z.getConstructor();
object object = constructor.newInstance();
method_ add.invoke(object,"reflection");
Method method_ get = clz.getMethod("get",int.class);
System.out.println(method_.get.invoke(object, 0));
两段代码的功能是一样的,但是 “正向” 操作的代码代码在编译之前,就需要明确要运行的类是(ArrayList),而第二段代码,只有在代码真正运行的时候,才知道运行的类是java.util.ArrayList。
说到这里你可能会有疑问:“反射有什么用呢?我明明已经知道了要使用的类,我直接new不就好了吗?”,这个说法当然是可以的,但是很多场景的情况下,在代码运行之前我们是并不知道要具体使用哪个类的,或者说在运行的时候才来决定到底使用哪个类。
反射的作用
比如有这么一个功能
1.“调用阿里云的人脸识别 API ”;这很简单,参考对方的 API 文档,很快就能实现。
2.好景不长,上线一个月后,领导说:“咱公司和腾讯云开始合作了,人脸识别接口改一下吧 ”
3.修改腾讯与接口使用了两个月后,领导:“换回来吧......”
那么这种情况下, 可能比较笨的办法就是写一个开关,用if-else来控制,如果哪天又换了别的接口,就加else-if,但是这并不是一个特别好的办法。
faceRecognition(bject faceImg){
if("AL" . equals(configStr)){
// 调用阿里云的人脸识别API
}else if("TX" .equals(configStr)){
//调用牌讯云的人脸识射API
}else if("AM" .equals(configStr)){
//调用亚马逊云的人股识别 API
}
}
如果我们使用反射机制呢?
//先创建一个接口
interface FaceRecognitionInterface(){
faceRecognition(object faceImg) ;
}
//多个实现类
class ALFaceRecognition implements FaceRecognitionInterface{
// 调用阿里云的人脸识别API的实现
}
class TXFaceRecognition implements FaceRecognitionInterface{
//调用腾讯云的人脸识别API的实现
}
//在使用人脸识别的代码中:
String configStr =“读取配置,走阿里云还是腾讯云";
FaceRecognitionInterface faceRe=Class.forName(configStr).newInstance();
faceRe.faceRecognition(faceImg);
这样一看是不是就能体会到反射的精妙了呢?同样的例子还有jdbc的驱动类:
public Connection getConnection() throws Exception{
Connection conn = null ;
//部始化驱动类
Class . forName("com . mysq1. jdbc .Driver");
conn = DriverManager . getConnection("jdbc: mysql://url","root", "admin");
return conn;
}
其中:
程序员 A 提供接口:Oracle 公司(之前的 Sun)提供 JDBC 标准(接口)。
程序员 B 提供实现:各个数据库厂商提供针对自家数据库的实现。
程序员 C 写客户端:我是码农在 Java 中敲代码访问数据库。
总结一下Java 反射的作用:可以设计出更为通用和灵活的架构,很多框架为了保证其通用性,可以根据配置加载不用的类,这时候要用到反射。除此之外:
动态代理:在不改变目标对象方法的情况下对方法进行增强,比如使用 AOP 拦截某些方法打印日志,这就需要通过反射执行方法中的内容。
注解:利用反射机制,获取注解并执行对应的行为。
简单再总结一点常用方法
上文中我们知道了 Java 运行期的源文件是 class 文件(字节码),所以要使用反射,那么就需要获取到字节码文件对象,在 Java 中,获取字节码文件对象有三种方式:
调用某个类的 class 属性:类名.class
调用对象的 getClass() 方法:对象.getClass()
使用 Class 类中的 forName() 静态方法:Class.forName(类的全路径) ,建议使用这种方法
java.lang.reflect 类库提供了对反射的支持:
Field :可以使用 get 和 set 方法读取和修改对象的属性;
Method :可以使用 invoke() 方法调用对象中的方法;
Constructor :可以用 newInstance() 创建新的对象。
反射的优缺点
优点:在运行时动态获取类和对象中的内容,极大地提高系统的灵活性和扩展性;夸张一些说,反射是框架设计的灵魂。
缺点:会有一定的性能损耗,JVM 无法对这些代码进行优化;破坏类的封装性。
总之,可能大家在平时的开发过程中,感觉自己并没有写过反射相关的代码,但是在我们用到的各种开源框架中,反射无处不在。