当前位置: 首页 > 科技观察

Java反射:框架设计的灵魂

时间:2023-03-11 23:07:10 科技观察

01.解释型语言和编译型语言会比编译型语言稍微差一些;例如JavaScript和Python;编译型语言:源代码在执行前需要通过编译器编译成机器码;如果代码在编译后需要修改,则需要在执行前重新编译。比如C语言;Java严格来说也是一种编译型语言,但介于编译型和解释型之间;Java不直接生成机器码而是生成中间码:在编译时将源代码交给编译器生成class文件(Bytecode),在这个过程中只做翻译工作,不放代码进入内存运行;进入运行时,字节码被Java虚拟机加载,解释成机器语言运行。02.动态语言和静态语言动态语言:是指程序可以在运行时改变自己的结构,在运行时确定数据类型,一个对象能否进行某种操作只取决于它是否有相应的方法,而不管它是否是某种类型的对象;例如JavaScript、Python。静态语言:相对于动态语言,变量的数据类型在编译时就已确定(使用变量前必须声明数据类型),编译时会匹配类型;如C语言、Java;03.ReflectiveConceptJava反射机制:在运行过程中,对于任何一个类,其所有的属性和方法都是可知的;对于任何对象,都可以调用它的属性和方法;这种动态获取类信息和调用对象方法的功能,就是Java的反射机制。既然反思有个“反”字,那我们先看看什么是“正”。在Java中,要使用类中的一个方法,“正向”是这样的:ArrayListlist=newArrayList();//Instantiatelist.add("reflection");//执行方法然后反向(反射)如何实现?Classclz=Class.forName("java.util.ArrayList");Methodmethod_add=clz.getMethod("add",Object.class);Constructorconstructor=clz.getConstructor();Objectobject=constructor.newInstance();method_add.invoke(object,"reflection");Methodmethod_get=clz.getMethod("get",int.class);System.out.println(method_get.invoke(object,0));两次代码执行的结果是一样的,但是在编译“forward”代码之前,已经明确了运行什么类(ArrayList),而第二段代码,只有在代码运行的时候,才知道那要运行的类就是java.util.ArrayList。04.反射的作用说到这里,可能有同学会有疑问:“反射有什么用?我已经知道要使用的类是ArrayList。不可以直接新建一个对象,执行里面的方法吗?”当然可以!但是很多场景下,代码运行前你并不知道使用哪个类,或者运行时决定使用哪个类;对于比如有这样一个函数:“调用阿里云的人脸识别API”,这个不简单,参考一下对方的API文档,很快就会实现。faceRecognition(ObjectfaceImg){//调用阿里云的人脸recognitionAPI}上线一个月后,负责人说:“我们公司已经开始和腾讯云合作了,我们改一下人脸识别接口吧。”faceRecognition(ObjectfaceImg){//调用腾讯云的人脸识别API}修改跑了两个月,领导说:“改回来”……当然,一些聪明的程序员会想到设置开关配置,让开关决定遵循哪一段代码逻辑。如果哪天领导想做亚马逊云服务,就继续写if-else:faceRecognition(ObjectfaceImg){if("AL".equals(configStr)){//调用阿里云的人脸识别API}elseif("TX".equals(configStr)){//调用腾讯云的人脸识别API}elseif("AM".equals(configStr)){//调用亚马逊云的人脸识别API}}但是有更好的方法:1.定义一个接口:interfaceFaceRecognitionInterface(){faceRecognition(ObjectfaceImg);}2。多个实现类:classALFaceRecognitionimplementsFaceRecognitionInterface{//调用阿里云人脸识别API实现}classTXFaceRecognitionimplementsFaceRecognitionInterface{//调用腾讯云人脸识别API实现}3.在调用人脸识别功能的代码中:StringconfigStr="读取配置,进入阿里云或腾讯云";FaceRecognitionInterfaceRe=Class.forName(configStr).newInstance();faceRe.faceRecognition(faceImg);在上面的例子中,你还是觉得在调用方法中做一个if-else判断和使用反射实现没有太大区别,但是如果程序员A提供接口,程序员B提供实现,程序员C写客户端呢?回忆一下JDBC的使用,比如创建连接:publicConnectiongetConnection()throwsException{Connectionconn=null;//初始化驱动类Class.forName("com.mysql.jdbc.Driver");conn=DriverManager.getConnection("jdbc:mysql://url","root","admin");returnconn;}其中:程序员A提供接口:Oracle公司(以前的Sun)提供了JDBC标准(接口)。程序员B提供实现:每个数据库供应商都为自己的数据库提供实现。程序员C写客户端:我等coder用Java敲代码访问数据库。总结一下Java反射的作用:可以设计出更通用、更灵活的架构。为了保证其通用性,很多框架可以根据配置加载不用的类。这时候就用到了反射。另外:动态代理:在不改变目标对象的方法的情况下增强方法,比如使用AOP拦截一些打印日志的方法,这就需要通过反射来执行方法中的内容。注解:利用反射机制获取注解并执行相应的行为。05.反射的使用上面我们知道Java运行时的源文件是class文件(字节码),所以要使用反射,需要得到字节码文件对象。在Java中,获取字节码文件对象有3种方法:调用某个类的class属性:类名.class调用对象的getClass()方法:object.getClass()使用forName()静态方法inClass类:Class.forName(类的完整路径),推荐使用该方法。java.lang.reflect类库提供了对反射的支持:Field:可以使用get和set方法读取和修改对象的属性;方法:可以使用invoke()方法调用对象中的方法;构造函数:可以使用newInstance()创建新对象。06.反射的优缺点优点:运行时动态获取类和对象的内容,大大提高了系统的灵活性和扩展性;说反射是框架设计的灵魂,也有些夸张。缺点:会有一定的性能损失,JVM无法优化这些代码;它会破坏类的封装。总之,你可能会觉得自己在平时的开发过程中没有写过反射相关的代码,但是在我们使用的各种开源框架中,反射无处不在。