前言:Java SSM框架里面经常用到反射机制,相信大家都用过Spring或者MyBatis等等这类框架,在使用这类框架的时候,免不了与该框架的XML配置文件打交道,在很多配置的地方都会填写一个全类名。看过源码的同学应该就知道,因为这些框架会先解析XML配置文得件得到这个全类名,然后通过这个全类名来得到Class对象,完成后面的反射调用的动作。比如Spring中,通过第三方配置文件实现对象的控制。只要在代码或配置文件中看到类的完全限定名(包名+类名),该Java Web框架底层原理基本上使用的就是Java反射机制。所以,为了更好学习Java后端框架,我们有必要理解这种Java反射机制。
一、反射机制概述
1、反射机制:无非就是先加载对应字节码中的类,然后根据加载类的信息,一点点的去解剖其中的内容。不管你是public的还是private的,亦或是本类的还是来自原继承关系或者实现接口中的方法和字段,我们Java的反射技术reflect,均可以将其从字节码中拉回到现实,不仅可以得到字段的名字,我们还可以获得字段的值和修改字段的值;不仅可以得到方法的申明我们还可以拿到方法的定义和唤起方法(执行方法)。
当然,我们会有这样的疑惑?
为什么, new一个对象那么简单,非要用反射技术中的newInstance()?
为什么,我可以直接对象a1. 变量访问变量,却非要用反射那么费劲的获得name字段呢?
为什么,我几行代码就能搞定的事情,非要用反射呢?
2、解密答案之前,我们先来思考一个问题?
假设我们定义了很多类,有Animal、Person、Car..... ,如果我想要一个Animal实例,那我就new Animal();如果另一个人想要一个Person实例,那么他需要new Person();当然,另一个说,我只要一个Car实例,于是它要new Car()......
这样就会导致,每个用户new的对象需求不相同,因此他们只能修改源代码,并重新编译才能生效。这种将new的对象写死在代码里的方法非常不灵活,因此,为了避免这种情况的方法,Java提供了反射机制。
反射是Java中一种强大的工具,能够使我们很方便的创建灵活的代码,通过反射运行配置文件内容,这些代码可以在运行时装配,无需在组件之间进行源代码链接,降低了代码的耦合度。但要注意反射使用不当的话会成本很高。
二、Spring中应用反射机制
new Animal();//我们必须指定Animal类来创建对象
new "Animal";//我们希望通过字符串就能承接一个Animal实例,而这个字符串我们可以放在配置文件中
典型的应用就是Spring,Spring就是将类的描述放在xx.xml配置文件中!!!
我们知道Spring的IOC吧,即“控制反转”(通过第三方配置文件实现对 对象的控制)。简单说是将我们设计好的对象交给容器控制,而不是直接交给程序内部进行对象的控制。
比如,在Spring中,我们经常看到:
针对上述的配置文件,我们Spring是怎么帮助我们实例化对象,并放到容器中去了呢? 没错,就是通过反射!!!!
我们看下下面的伪代码实现过程:
//解析<bean .../>元素的id属性得到该字符串值为"sqlSessionFactory"
String idStr = "sqlSessionFactory";
//解析<bean .../>元素的class属性得到该字符串值
为"org.mybatis.spring.SqlSessionFactoryBean"
String classStr = "org.mybatis.spring.SqlSessionFactoryBean";
//利用反射知识,通过classStr获取Class类对象
Class cls = Class.forName(classStr);
//实例化对象
Object obj = cls.newInstance();
//container表示Spring容器
container.put(idStr, obj);
//当一个类里面需要用另一类的对象时,我们继续下面的操作
//解析<property .../>元素的name属性得到该字符串值为“dataSource”
String nameStr = "dataSource";
//解析<property .../>元素的ref属性得到该字符串值为“dataSource”
String refStr = "dataSource";
//生成将要调用setter方法名
String setterName = "set" + nameStr.substring(0, 1).toUpperCase()
+ nameStr.substring(1);
//获取spring容器中名为refStr的Bean,该Bean将会作为传入参数
Object paramBean = container.get(refStr);
//获取setter方法的Method类,此处的cls是刚才反射代码得到的Class对象
Method setter = cls.getMethod(setterName, paramBean.getClass());
//调用invoke()方法,此处的obj是刚才反射代码得到的Object对象
setter.invoke(obj, paramBean);
是不是很熟悉,虽然是伪代码,但是和我们上篇讲的反射机制的使用是相同的,现在知道我们的反射机制用在哪了吧,没错就是我们经常提到的Java web框架中,里面就用到了反射机制,只要在代码或配置文件中看到类的完全限定名(包名+类名),其底层原理基本上使用的就是Java的反射机制。
所以,如果你不做框架的话,基本上是用不到反射机制的,我们大多时候是使用框架的一方,而反射机制都已经在底层实现过,我们就不必担心会写那么复杂的代码。但为了更好学习Java后端框架,我们还是有必要理了解一下Java反射机制。