反射的定義:
反射是java語言的一個特性,它允程序在運行時(注意不是編譯的時候)來進行自我檢查並且對內部的成員進行操作。例如它允許一個java的類獲取它所有的成員變量和方法並且顯示出來。
反射機制的優點與缺點
首先要搞清楚為什么要用反射機制?直接創建對象不就可以了嗎,這就涉及到了動態與靜態的概念。
靜態編譯:在編譯時確定類型,綁定對象,即通過。
動態編譯:運行時確定類型,綁定對象。動態編譯最大限度發揮了java的靈活性,體現了多態的應用,有以降低類之間的藕合性。
反射機制的優點:可以實現動態創建對象和編譯,體現出很大的靈活性(特別是在J2EE的開發中它的靈活性就表現的十分明顯)。通過反射機制我們可以獲得類的各種內容,進行了反編譯。對於JAVA這種先編譯再運行的語言來說,反射機制可以使代碼更加靈活,更加容易實現面向對象。
比如,一個大型的軟件,不可能一次就把把它設計的很完美,當這個程序編譯后,發布了,當發現需要更新某些功能時,我們不可能要用戶把以前的卸載,再重新安裝新的版本,假如這樣的話,這個軟件肯定是沒有多少人用的。采用靜態的話,需要把整個程序重新編譯一次才可以實現功能的更新,而采用反射機制的話,它就可以不用卸載,只需要在運行時才動態的創建和編譯,就可以實現該功能。
反射機制的缺點:對性能有影響。使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什么並且它 滿足我們的要求。這類操作總是慢於只直接執行相同的操作。
IOC:即“控制反轉”,不是什么技術,而是一種思想。使用IOC意味着將你設計好的對象交給容器控制,而不是傳統的在你的對象內部直接控制。
在spring的配置文件中,經常看到如下配置:
- <bean id="courseDao" class="com.qcjy.learning.Dao.impl.CourseDaoImpl"></bean>
那么通過這樣配置,Spring是怎么幫我們實例化對象,並且放到容器中去了了?對,就是通過反射!!!
下面是Spring通過配置進行實例化對象,並放到容器中的偽代碼:
- //解析<bean .../>元素的id屬性得到該字符串值為“courseDao”
- String idStr = "courseDao";
- //解析<bean .../>元素的class屬性得到該字符串值為“com.qcjy.learning.Dao.impl.CourseDaoImpl”
- String classStr = "com.qcjy.learning.Dao.impl.CourseDaoImpl";
- //利用反射知識,通過classStr獲取Class類對象
- Class<?> cls = Class.forName(classStr);
- //實例化對象
- Object obj = cls.newInstance();
- //container表示Spring容器
- container.put(idStr, obj);
通過解析xml文件,獲取到id屬性和class屬性里面的內容,利用反射原理獲取到配置里面類的實例對象,存入到Spring的bean容器中。
當一個類里面需要應用另一類的對象時,Spring的配置如下所示:
- <bean id="courseService" class="com.qcjy.learning.service.impl.CourseServiceImpl">
- <!-- 控制調用setCourseDao()方法,將容器中的courseDao bean作為傳入參數 -->
- <property name="courseDao" ref="courseDao"></property>
- </bean>
我們繼續用偽代碼的形式來模擬實現一下Spring底層處理原理:
- //解析<property .../>元素的name屬性得到該字符串值為“courseDao”
- String nameStr = "courseDao";
- //解析<property .../>元素的ref屬性得到該字符串值為“courseDao”
- String refStr = "courseDao";
- //生成將要調用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);
通過上面對Spring底層原理的分析,可以發現,其實並不難,用到的都是反射機制,通過反射實例化對象,存入到Spring的bean容器中。
只要在代碼或配置文件中看到類的完整路徑(包.類),其底層原理基本上使用的就是Java的反射機制。