近期在維護公司項目的時候遇到一個問題,因為實體類中的 set 方法涉及到了業(yè)務(wù)邏輯,因此在給對象賦值的過程中不能夠使用 set 方法,為了實現(xiàn)功能,所以采用了反射的機制給對象屬性賦值,借此機會也了解了反射的一些具體用法和使用場景,分以下兩點對反射進行分析:
反射的優(yōu)勢和劣勢
反射的應(yīng)用場景
反射的優(yōu)勢和劣勢??個人理解,反射機制實際上就是上帝模式,如果說方法的調(diào)用是 Java 正確的打開方式,那反射機制就是上帝偷偷開的后門,只要存在對應(yīng)的class,一切都能夠被調(diào)用。
??那上帝為什么要打開這個后門呢?這涉及到了靜態(tài)和動態(tài)的概念
靜態(tài)編譯:在編譯時確定類型,綁定對象
動態(tài)編譯:運行時確定類型,綁定對象
??兩者的區(qū)別在于,動態(tài)編譯可以最大程度地支持多態(tài),而多態(tài)最大的意義在于降低類的耦合性,因此反射的優(yōu)點就很明顯了:解耦以及提高代碼的靈活性。
??因此,反射的優(yōu)勢和劣勢分別在于:
優(yōu)勢
運行期類型的判斷,動態(tài)類加載:提高代碼靈活度
劣勢
性能瓶頸:反射相當(dāng)于一系列解釋操作,通知 JVM 要做的事情,性能比直接的java代碼要慢很多
反射的應(yīng)用場景??在我們平時的項目開發(fā)過程中,基本上很少會直接使用到反射機制,但這不能說明反射機制沒有用,實際上有很多設(shè)計、開發(fā)都與反射機制有關(guān),例如模塊化的開發(fā),通過反射去調(diào)用對應(yīng)的字節(jié)碼;動態(tài)代理設(shè)計模式也采用了反射機制,還有我們?nèi)粘J褂玫?Spring/Hibernate 等框架,也是利用CGLIB 反射機制才得以實現(xiàn),下面就舉例最常見的兩個例子,來說明反射機制的強大之處:
JDBC 的數(shù)據(jù)庫的連接
在JDBC 的操作中,如果要想進行數(shù)據(jù)庫的連接,則必須按照以上的幾步完成
通過Class.forName()加載數(shù)據(jù)庫的驅(qū)動程序 (通過反射加載,前提是引入相關(guān)了Jar包)
通過 DriverManager 類進行數(shù)據(jù)庫的連接,連接的時候要輸入數(shù)據(jù)庫的連接地址、用戶名、密碼
通過Connection 接口接收連接
public class ConnectionJDBC { /** * @param args */ //驅(qū)動程序就是之前在classpath中配置的JDBC的驅(qū)動程序的JAR 包中 public static final String DBDRIVER = "com.mysql.jdbc.Driver"; //連接地址是由各個數(shù)據(jù)庫生產(chǎn)商多帶帶提供的,所以需要多帶帶記住 public static final String DBURL = "jdbc:mysql://localhost:3306/test"; //連接數(shù)據(jù)庫的用戶名 public static final String DBUSER = "root"; //連接數(shù)據(jù)庫的密碼 public static final String DBPASS = ""; public static void main(String[] args) throws Exception { Connection con = null; //表示數(shù)據(jù)庫的連接對象 Class.forName(DBDRIVER); //1、使用CLASS 類加載驅(qū)動程序 ,反射機制的體現(xiàn) con = DriverManager.getConnection(DBURL,DBUSER,DBPASS); //2、連接數(shù)據(jù)庫 System.out.println(con); con.close(); // 3、關(guān)閉數(shù)據(jù)庫 }
Spring 框架的使用
??在 Java的反射機制在做基礎(chǔ)框架的時候非常有用,行內(nèi)有一句這樣的老話:反射機制是Java框架的基石。一般應(yīng)用層面很少用,不過這種東西,現(xiàn)在很多開源框架基本都已經(jīng)封裝好了,自己基本用不著寫。典型的除了hibernate之外,還有spring也用到很多反射機制。最經(jīng)典的就是xml的配置模式。
Spring 通過 XML 配置模式裝載 Bean 的過程:
將程序內(nèi)所有 XML 或 Properties 配置文件加載入內(nèi)存中
Java類里面解析xml或properties里面的內(nèi)容,得到對應(yīng)實體類的字節(jié)碼字符串以及相關(guān)的屬性信息
使用反射機制,根據(jù)這個字符串獲得某個類的Class實例
動態(tài)配置實例的屬性
Spring這樣做的好處是:
不用每一次都要在代碼里面去new或者做其他的事情
以后要改的話直接改配置文件,代碼維護起來就很方便了
有時為了適應(yīng)某些需求,Java類里面不一定能直接調(diào)用另外的方法,可以通過反射機制來實現(xiàn)
模擬 Spring 加載 XML 配置文件:
public class BeanFactory { private MapbeanMap = new HashMap (); /** * bean工廠的初始化. * @param xml xml配置文件 */ public void init(String xml) { try { //讀取指定的配置文件 SAXReader reader = new SAXReader(); ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); //從class目錄下獲取指定的xml文件 InputStream ins = classLoader.getResourceAsStream(xml); Document doc = reader.read(ins); Element root = doc.getRootElement(); Element foo; //遍歷bean for (Iterator i = root.elementIterator("bean"); i.hasNext();) { foo = (Element) i.next(); //獲取bean的屬性id和class Attribute id = foo.attribute("id"); Attribute cls = foo.attribute("class"); //利用Java反射機制,通過class的名稱獲取Class對象 Class bean = Class.forName(cls.getText()); //獲取對應(yīng)class的信息 java.beans.BeanInfo info = java.beans.Introspector.getBeanInfo(bean); //獲取其屬性描述 java.beans.PropertyDescriptor pd[] = info.getPropertyDescriptors(); //設(shè)置值的方法 Method mSet = null; //創(chuàng)建一個對象 Object obj = bean.newInstance(); //遍歷該bean的property屬性 for (Iterator ite = foo.elementIterator("property"); ite.hasNext();) { Element foo2 = (Element) ite.next(); //獲取該property的name屬性 Attribute name = foo2.attribute("name"); String value = null; //獲取該property的子元素value的值 for(Iterator ite1 = foo2.elementIterator("value"); ite1.hasNext();) { Element node = (Element) ite1.next(); value = node.getText(); break; } for (int k = 0; k < pd.length; k++) { if (pd[k].getName().equalsIgnoreCase(name.getText())) { mSet = pd[k].getWriteMethod(); //利用Java的反射極致調(diào)用對象的某個set方法,并將值設(shè)置進去 mSet.invoke(obj, value); } } } //將對象放入beanMap中,其中key為id值,value為對象 beanMap.put(id.getText(), obj); } } catch (Exception e) { System.out.println(e.toString()); } } //other codes }
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/67352.html
摘要:反射機制是什么反射機制是在運行狀態(tài)中,對于任意一個類,都能夠知道這個類的所有屬性和方法對于任意一個對象,都能夠調(diào)用它的任意一個方法和屬性這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法的功能稱為語言的反射機制反射機制能做什么反射機制主要提供了以下功 反射機制是什么 反射機制是在運行狀態(tài)中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調(diào)用它的任意一個方法和屬性;這種...
摘要:的動態(tài)性反射機制動態(tài)編譯動態(tài)執(zhí)行代碼動態(tài)字節(jié)碼操作動態(tài)語言程序運行時可以改變程序得結(jié)構(gòu)或變量類型典型語言等如下代碼不是動態(tài)語言但有一定的動態(tài)性我們可以利用反射機制字節(jié)碼操作獲得類似動態(tài)語言的特性的動態(tài)性讓編程的時候更加靈活反射機制反射機制指 1.Java的動態(tài)性 反射機制 動態(tài)編譯 動態(tài)執(zhí)行JavaScript代碼 動態(tài)字節(jié)碼操作 2.動態(tài)語言 程序運行時,可以改變程序得結(jié)構(gòu)或變量...
摘要:效率運行效率使用反射減低程序的運行效率。開發(fā)效率由于反射運用到各個框架中,大大加快了開發(fā)的效率。 反射的核心就是Class對象,每一個類被jvm加載都會有一個對應(yīng)的class對象,這個class對象包含了這個類的結(jié)構(gòu)信息,反射就是會通過反射api反復(fù)操作這個class對象(屬性,方法,注解,構(gòu)造器,泛型),但是反射會降低程序的運行效率,比普通方法要慢30倍,通過setAccessble...
摘要:反射提供給面向?qū)ο缶幊炭梢宰允〉哪芰?,即反射。在簡單工廠模式中,根據(jù)傳遞的參數(shù)來返回不同的類的實例簡單工廠模式又稱為靜態(tài)工廠方法模式。也就是簡單工廠模式工廠工廠類。PHP高級特性-反射以及工廠設(shè)計模式的結(jié)合使用 [結(jié)合 Laravel-Admin 代碼實例講解]利用反射來實現(xiàn)工廠模式的生產(chǎn)而無需創(chuàng)建特定的工廠類本文地址http://janrs.com/?p=833轉(zhuǎn)載無需經(jīng)過作者本人授權(quán)轉(zhuǎn)載...
摘要:與都繼承自類,在中也是使用字符數(shù)組保存字符串,,這兩種對象都是可變的。采用字節(jié)碼的好處語言通過字節(jié)碼的方式,在一定程度上解決了傳統(tǒng)解釋型語言執(zhí)行效率低的問題,同時又保留了解釋型語言可移植的特點。 String和StringBuffer、StringBuilder的區(qū)別是什么?String為什么是不可變的? String和StringBuffer、StringBuilder的區(qū)別 可變性...
閱讀 1279·2021-10-11 10:57
閱讀 2051·2021-09-02 15:15
閱讀 1613·2019-08-30 15:56
閱讀 1205·2019-08-30 15:55
閱讀 1163·2019-08-30 15:44
閱讀 985·2019-08-29 12:20
閱讀 1331·2019-08-29 11:12
閱讀 1073·2019-08-28 18:29