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