<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試官:Java 反射機(jī)制的應(yīng)用場景?

          共 4743字,需瀏覽 10分鐘

           ·

          2021-11-14 08:59


          作者:Seven_Nee

          來源:https://segmentfault.com/a/1190000010162647


          近期在維護(hù)公司項(xiàng)目的時(shí)候遇到一個(gè)問題,因?yàn)閷?shí)體類中的 set 方法涉及到了業(yè)務(wù)邏輯,因此在給對象賦值的過程中不能夠使用 set 方法,為了實(shí)現(xiàn)功能,所以采用了反射的機(jī)制給對象屬性賦值,借此機(jī)會(huì)也了解了反射的一些具體用法和使用場景,分以下兩點(diǎn)對反射進(jìn)行分析:

          • 反射的優(yōu)勢和劣勢
          • 反射的應(yīng)用場景

          反射的優(yōu)勢和劣勢

          個(gè)人理解,反射機(jī)制實(shí)際上就是上帝模式,如果說方法的調(diào)用是 Java 正確的打開方式,那反射機(jī)制就是上帝偷偷開的后門,只要存在對應(yīng)的class,一切都能夠被調(diào)用。

          那上帝為什么要打開這個(gè)后門呢?

          這涉及到了靜態(tài)和動(dòng)態(tài)的概念:

          • 靜態(tài)編譯:在編譯時(shí)確定類型,綁定對象
          • 動(dòng)態(tài)編譯:運(yùn)行時(shí)確定類型,綁定對象

          兩者的區(qū)別在于,動(dòng)態(tài)編譯可以最大程度地支持多態(tài),而多態(tài)最大的意義在于降低類的耦合性,因此反射的優(yōu)點(diǎn)就很明顯了:解耦以及提高代碼的靈活性。

          因此,反射的優(yōu)勢和劣勢分別在于:

          優(yōu)勢

          運(yùn)行期類型的判斷,動(dòng)態(tài)類加載:提高代碼靈活度

          劣勢

          性能瓶頸:反射相當(dāng)于一系列解釋操作,通知 JVM 要做的事情,性能比直接的java代碼要慢很多。

          反射的應(yīng)用場景

          在我們平時(shí)的項(xiàng)目開發(fā)過程中,基本上很少會(huì)直接使用到反射機(jī)制,但這不能說明反射機(jī)制沒有用,實(shí)際上有很多設(shè)計(jì)、開發(fā)都與反射機(jī)制有關(guān),例如模塊化的開發(fā),通過反射去調(diào)用對應(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ù)庫的連接

          在JDBC 的操作中,如果要想進(jìn)行數(shù)據(jù)庫的連接,則必須按照以上的幾步完成

          1. 通過Class.forName()加載數(shù)據(jù)庫的驅(qū)動(dòng)程序 (通過反射加載,前提是引入相關(guān)了Jar包)
          2. 通過 DriverManager 類進(jìn)行數(shù)據(jù)庫的連接,連接的時(shí)候要輸入數(shù)據(jù)庫的連接地址、用戶名、密碼
          3. 通過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ù)庫生產(chǎn)商單獨(dú)提供的,所以需要單獨(dú)記住??
          ????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ū)動(dòng)程序?,反射機(jī)制的體現(xiàn)?
          ????????con?=?DriverManager.getConnection(DBURL,DBUSER,DBPASS);?//2、連接數(shù)據(jù)庫??
          ????????System.out.println(con);??
          ????????con.close();?//?3、關(guān)閉數(shù)據(jù)庫??
          ????}??

          Spring 框架的使用

          在 Java的反射機(jī)制在做基礎(chǔ)框架的時(shí)候非常有用,行內(nèi)有一句這樣的老話:反射機(jī)制是Java框架的基石。一般應(yīng)用層面很少用,不過這種東西,現(xiàn)在很多開源框架基本都已經(jīng)封裝好了,自己基本用不著寫。

          典型的除了hibernate之外,還有spring也用到很多反射機(jī)制。最經(jīng)典的就是xml的配置模式。

          Spring 通過 XML 配置模式裝載 Bean 的過程:

          1. 將程序內(nèi)所有 XML 或 Properties 配置文件加載入內(nèi)存中
          2. Java類里面解析xml或properties里面的內(nèi)容,得到對應(yīng)實(shí)體類的字節(jié)碼字符串以及相關(guān)的屬性信息
          3. 使用反射機(jī)制,根據(jù)這個(gè)字符串獲得某個(gè)類的Class實(shí)例
          4. 動(dòng)態(tài)配置實(shí)例的屬性

          Spring這樣做的好處是:

          • 不用每一次都要在代碼里面去new或者做其他的事情
          • 以后要改的話直接改配置文件,代碼維護(hù)起來就很方便了
          • 有時(shí)為了適應(yīng)某些需求,Java類里面不一定能直接調(diào)用另外的方法,可以通過反射機(jī)制來實(shí)現(xiàn)

          模擬 Spring 加載 XML 配置文件:

          public?class?BeanFactory?{
          ???????private?Map?beanMap?=?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對象
          ????????????????????????????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)建一個(gè)對象
          ????????????????????????????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???????????????????????????????????????????if?(pd[k].getName().equalsIgnoreCase(name.getText()))?{
          ?????????????????????????????????????????????????mSet?=?pd[k].getWriteMethod();
          ?????????????????????????????????????????????????//利用Java的反射極致調(diào)用對象的某個(gè)set方法,并將值設(shè)置進(jìn)去
          ?????????????????????????????????????????????????mSet.invoke(obj,?value);
          ??????????????????????????????????????????}
          ???????????????????????????????????}
          ????????????????????????????}
          ???????????????????????????
          ????????????????????????????//將對象放入beanMap中,其中key為id值,value為對象
          ????????????????????????????beanMap.put(id.getText(),?obj);
          ?????????????????????}
          ??????????????}?catch?(Exception?e)?{
          ?????????????????????System.out.println(e.toString());
          ??????????????}
          ???????}
          ??????
          ???????//other?codes
          }

          程序汪資料鏈接

          程序汪接的7個(gè)私活都在這里,經(jīng)驗(yàn)整理

          Java項(xiàng)目分享 ?最新整理全集,找項(xiàng)目不累啦 05版

          堪稱神級的Spring Boot手冊,從基礎(chǔ)入門到實(shí)戰(zhàn)進(jìn)階

          臥槽!字節(jié)跳動(dòng)《算法中文手冊》火了,完整版 PDF 開放下載!

          臥槽!阿里大佬總結(jié)的《圖解Java》火了,完整版PDF開放下載!

          字節(jié)跳動(dòng)總結(jié)的設(shè)計(jì)模式 PDF 火了,完整版開放下載!


          歡迎添加程序汪個(gè)人微信 itwang009? 進(jìn)粉絲群或圍觀朋友圈

          瀏覽 54
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产乱伦一区二区三区 | 久久大香蕉伊人一区二区 | 蜜桃亚洲无码电影 | 北条麻妃精品99青青久久 | 亚洲成人网 在线观看 |