<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>

          Class.forName 和 ClassLoader 到底有啥區(qū)別?

          共 5116字,需瀏覽 11分鐘

           ·

          2020-09-16 02:25


          作者 |?紀(jì)莫

          來源 |?https://www.cnblogs.com/jimoer/p/9185662.html

          前言

          最近在面試過程中有被問到,在Java反射中Class.forName()加載類和使用ClassLoader加載類的區(qū)別。當(dāng)時沒有想出來后來自己研究了一下就寫下來記錄一下。

          解釋

          在java中Class.forName()和ClassLoader都可以對類進(jìn)行加載。ClassLoader就是遵循雙親委派模型最終調(diào)用啟動類加載器的類加載器,實現(xiàn)的功能是“通過一個類的全限定名來獲取描述此類的二進(jìn)制字節(jié)流”,獲取到二進(jìn)制流后放到JVM中。Class.forName()方法實際上也是調(diào)用的ClassLoader來實現(xiàn)的。

          Class.forName(String className);這個方法的源碼是

          @CallerSensitive
          public?static?Class?forName(String?className)
          ????????????throws?ClassNotFoundException?{
          ????Class?caller?=?Reflection.getCallerClass();
          ????return?forName0(className,?true,?ClassLoader.getClassLoader(caller),?caller);
          }

          最后調(diào)用的方法是forName0這個方法,在這個forName0方法中的第二個參數(shù)被默認(rèn)設(shè)置為了true,這個參數(shù)代表是否對加載的類進(jìn)行初始化,設(shè)置為true時會類進(jìn)行初始化,代表會執(zhí)行類中的靜態(tài)代碼塊,以及對靜態(tài)變量的賦值等操作。

          也可以調(diào)用Class.forName(String name, boolean initialize,ClassLoader loader)方法來手動選擇在加載類的時候是否要對類進(jìn)行初始化。Class.forName(String name, boolean initialize,ClassLoader loader)的源碼如下:

          /*?@param?name???????fully?qualified?name?of?the?desired?class
          ?*?@param?initialize?if?{@code?true}?the?class?will?be?initialized.
          ?*???????????????????See?Section?12.4?of?The?Java?Language?Specification.
          ?*?@param?loader?????class?loader?from?which?the?class?must?be?loaded
          ?*?@return???????????class?object?representing?the?desired?class
          ?*
          ?*?@exception?LinkageError?if?the?linkage?fails
          ?*?@exception?ExceptionInInitializerError?if?the?initialization?provoked
          ?*????????????by?this?method?fails
          ?*?@exception?ClassNotFoundException?if?the?class?cannot?be?located?by
          ?*????????????the?specified?class?loader
          ?*
          ?*?@see???????java.lang.Class#forName(String)
          ?*?@see???????java.lang.ClassLoader
          ?*?@since?????1.2?????*/

          @CallerSensitive
          public?static?Class?forName(String?name,?boolean?initialize,
          ???????????????????????????????ClassLoader?loader)
          ????throws?ClassNotFoundException
          {
          ????Class?caller?=?null;
          ????SecurityManager?sm?=?System.getSecurityManager();
          ????if?(sm?!=?null)?{
          ????????//?Reflective?call?to?get?caller?class?is?only?needed?if?a?security?manager
          ????????//?is?present.??Avoid?the?overhead?of?making?this?call?otherwise.
          ????????caller?=?Reflection.getCallerClass();
          ????????if?(sun.misc.VM.isSystemDomainLoader(loader))?{
          ????????????ClassLoader?ccl?=?ClassLoader.getClassLoader(caller);
          ????????????if?(!sun.misc.VM.isSystemDomainLoader(ccl))?{
          ????????????????sm.checkPermission(
          ????????????????????SecurityConstants.GET\_CLASSLOADER\_PERMISSION);
          ????????????}
          ????????}
          ????}
          ????return?forName0(name,?initialize,?loader,?caller);
          }

          源碼中的注釋只摘取了一部分,其中對參數(shù)initialize的描述是:if {@code true} the class will be initialized.意思就是說:如果參數(shù)為true,則加載的類將會被初始化。

          舉例

          下面還是舉例來說明結(jié)果吧:

          一個含有靜態(tài)代碼塊、靜態(tài)變量、賦值給靜態(tài)變量的靜態(tài)方法的類

          public?class?ClassForName?{

          ????//靜態(tài)代碼塊
          ????static?{
          ????????System.out.println("執(zhí)行了靜態(tài)代碼塊");
          ????}
          ????//靜態(tài)變量
          ????private?static?String?staticFiled?=?staticMethod();

          ????//賦值靜態(tài)變量的靜態(tài)方法
          ????public?static?String?staticMethod(){
          ????????System.out.println("執(zhí)行了靜態(tài)方法");
          ????????return?"給靜態(tài)字段賦值了";
          ????}

          }

          使用Class.forName()的測試方法:

          @Test
          public?void?test45()
          {
          ????try?{
          ????????ClassLoader.getSystemClassLoader().loadClass("com.eurekaclient2.client2.ClassForName");
          ????????System.out.println("#########-------------結(jié)束符------------##########");
          ????}?catch?(ClassNotFoundException?e)?{
          ????????e.printStackTrace();
          ????}
          }

          運行結(jié)果:

          執(zhí)行了靜態(tài)代碼塊執(zhí)行了靜態(tài)方法#########-------------結(jié)束符------------##########??

          使用ClassLoader的測試方法:

          @Test
          public?void?test45()
          {
          ????try?{
          ????????ClassLoader.getSystemClassLoader().loadClass("com.eurekaclient2.client2.ClassForName");
          ????????System.out.println("#########-------------結(jié)束符------------##########");
          ????}?catch?(ClassNotFoundException?e)?{
          ????????e.printStackTrace();
          ????}
          }

          運行結(jié)果:

          #########-------------結(jié)束符------------##########

          根據(jù)運行結(jié)果得出Class.forName加載類時將類進(jìn)了初始化,而ClassLoader的loadClass并沒有對類進(jìn)行初始化,只是把類加載到了虛擬機中。

          應(yīng)用場景

          在我們熟悉的Spring框架中的IOC的實現(xiàn)就是使用的ClassLoader。

          而在我們使用JDBC時通常是使用Class.forName()方法來加載數(shù)據(jù)庫連接驅(qū)動。這是因為在JDBC規(guī)范中明確要求Driver(數(shù)據(jù)庫驅(qū)動)類必須向DriverManager注冊自己。

          以MySQL的驅(qū)動為例解釋:

          public?class?Driver?extends?NonRegisteringDriver?implements?java.sql.Driver?{??
          ????//?~?Static?fields/initializers??
          ????//?---------------------------------------------??

          ????//??
          ????//?Register?ourselves?with?the?DriverManager??
          ????//??
          ????static?{??
          ????????try?{??
          ????????????java.sql.DriverManager.registerDriver(new?Driver());??
          ????????}?catch?(SQLException?E)?{??
          ????????????throw?new?RuntimeException("Can't?register?driver!");??
          ????????}??
          ????}??

          ????//?~?Constructors??
          ????//?-----------------------------------------------------------??

          ????/**?
          ?????*?Construct?a?new?driver?and?register?it?with?DriverManager?
          ?????*??
          ?????*?@throws?SQLException?
          ?????*?????????????if?a?database?error?occurs.?
          ?????*/
          ??
          ????public?Driver()?throws?SQLException?{??
          ????????//?Required?for?Class.forName().newInstance()??????}??

          }

          我們看到Driver注冊到DriverManager中的操作寫在了靜態(tài)代碼塊中,這就是為什么在寫JDBC時使用Class.forName()的原因了。關(guān)注微信公眾號:Java技術(shù)棧,在后臺回復(fù):java,可以獲取我整理的 N 篇最新 Java?教程,都是干貨。

          好了,今天就寫到這了,最近在面試,遇到了很多問題,也學(xué)習(xí)了不少,雖然很累,但是也讓人成長了不少,畢竟面試就是一個脫皮的過程,會遇到各種企業(yè)各種面試官各種問題,各種場景。

          給自己加油吧,找一個最少能讓自己干個幾年的公司,別總是讓我遇到工作了沒多久公司就垮掉的這種就行了。要不我也很無奈啊。

          等找到工作后,會總結(jié)自己面經(jīng)的。

          - 推薦閱讀 -


          架構(gòu)師離職后,成為自由開發(fā)者的第 100 天


          下方二維碼關(guān)注我

          互聯(lián)網(wǎng)草根,堅持分享技術(shù)、創(chuàng)業(yè)產(chǎn)品心得和總結(jié)~



          點擊“閱讀原文”,領(lǐng)取 2020 年最新免費技術(shù)資料大全

          ↓↓↓?
          瀏覽 38
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  色情视频在线观看免费 | 丁香五月综合激清 | 五月天乱伦 | 翔田千里无码一区二区三区 | 婷婷五月天婷婷五月天婷婷五月天色 |