<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)用場(chǎng)景?

          共 4772字,需瀏覽 10分鐘

           ·

          2021-11-16 02:59

          點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”

          優(yōu)質(zhì)文章,第一時(shí)間送達(dá)

          作者:Seven_Nee

          來(lái)源:https://segmentfault.com/a/1190000010162647


          近期在維護(hù)公司項(xiàng)目的時(shí)候遇到一個(gè)問(wèn)題,因?yàn)閷?shí)體類(lèi)中的 set 方法涉及到了業(yè)務(wù)邏輯,因此在給對(duì)象賦值的過(guò)程中不能夠使用 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í)際上就是上帝模式,如果說(shuō)方法的調(diào)用是 Java 正確的打開(kāi)方式,那反射機(jī)制就是上帝偷偷開(kāi)的后門(mén),只要存在對(duì)應(yīng)的class,一切都能夠被調(diào)用。

          那上帝為什么要打開(kāi)這個(gè)后門(mén)呢?

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

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

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

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

          優(yōu)勢(shì)

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

          劣勢(shì)

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

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

          在我們平時(shí)的項(xiàng)目開(kāi)發(fā)過(guò)程中,基本上很少會(huì)直接使用到反射機(jī)制,但這不能說(shuō)明反射機(jī)制沒(méi)有用,實(shí)際上有很多設(shè)計(jì)、開(kāi)發(fā)都與反射機(jī)制有關(guān),例如模塊化的開(kāi)發(fā),通過(guò)反射去調(diào)用對(duì)應(yīng)的字節(jié)碼。

          動(dòng)態(tài)代理設(shè)計(jì)模式也采用了反射機(jī)制,還有我們?nèi)粘J褂玫?Spring/Hibernate 等框架,也是利用CGLIB 反射機(jī)制才得以實(shí)現(xiàn),下面就舉例最常見(jiàn)的兩個(gè)例子,來(lái)說(shuō)明反射機(jī)制的強(qiáng)大之處。

          JDBC 的數(shù)據(jù)庫(kù)的連接

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

          1. 通過(guò)Class.forName()加載數(shù)據(jù)庫(kù)的驅(qū)動(dòng)程序 (通過(guò)反射加載,前提是引入相關(guān)了Jar包)
          2. 通過(guò) DriverManager 類(lèi)進(jìn)行數(shù)據(jù)庫(kù)的連接,連接的時(shí)候要輸入數(shù)據(jù)庫(kù)的連接地址、用戶(hù)名、密碼
          3. 通過(guò)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)商單獨(dú)提供的,所以需要單獨(dú)記住??
          ????public?static?final?String?DBURL?=?"jdbc:mysql://localhost:3306/test";??
          ????//連接數(shù)據(jù)庫(kù)的用戶(hù)名??
          ????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?類(lèi)加載驅(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)有一句這樣的老話(huà):反射機(jī)制是Java框架的基石。一般應(yīng)用層面很少用,不過(guò)這種東西,現(xiàn)在很多開(kāi)源框架基本都已經(jīng)封裝好了,自己基本用不著寫(xiě)。

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

          Spring 通過(guò) XML 配置模式裝載 Bean 的過(guò)程:

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

          Spring這樣做的好處是:

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

          模擬 Spring 加載 XML 配置文件:

          public?class?BeanFactory?{
          ???????private?Map?beanMap?=?new?HashMap();
          ???????/**
          ???????*?bean工廠(chǎng)的初始化.
          ???????*?@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ī)制,通過(guò)class的名稱(chēng)獲取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???????????????????????????????????????????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
          }
          瀏覽 36
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(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>
                  国产高清无码在线观看视频 | 亚洲小学生妹三级毛片视频大全 | 精品一区二区三区四区五区六区七区 | 日逼免费观看网站 | 2024国产精品 |