<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ī)制

          共 6013字,需瀏覽 13分鐘

           ·

          2021-04-10 10:50

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

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

          反射機(jī)制的概念:

          反射機(jī)制是指在程序運(yùn)行過(guò)程中,對(duì)任意一個(gè)類都能夠獲取其所有屬性和方法,并且對(duì)任意一個(gè)對(duì)象都能調(diào)用其任意一個(gè)方法。這種動(dòng)態(tài)獲取類和對(duì)象的信息,以及動(dòng)態(tài)調(diào)用對(duì)象的方法的功能被稱為Java語(yǔ)言的反射機(jī)制。


          Class類的介紹:

          說(shuō)到反射,就不得不提起java.lang.Class這個(gè)類,JVM為每個(gè)加載的class創(chuàng)建了對(duì)應(yīng)的Class實(shí)例,并在實(shí)例中保存了該class的所有信息,包括類名、包名、父類、實(shí)現(xiàn)的接口、所有方法、字段等。那么Class到底是個(gè)什么類呢?先看下它的部分源碼:

          public final class Class<T> implements java.io.Serializable,
                                        GenericDeclaration,
                                        Type,
                                        AnnotatedElement {
              private Class(ClassLoader loader) {
                  classLoader = loader;
              }
          }

          可以看出這個(gè)類被聲明為final(不可變類),并且它的構(gòu)造方法是private(私有的),即不可能通過(guò)new關(guān)鍵字來(lái)創(chuàng)建該實(shí)例,但是否可以通過(guò)反射機(jī)制(很強(qiáng)大)來(lái)創(chuàng)建那些構(gòu)造方法為私有的類的實(shí)例呢?答案是幾乎都可以,但Class這個(gè)類例外,下面可以來(lái)驗(yàn)證一下:

          自定義一個(gè)構(gòu)造方法是私有的類Test

          class Test {
              private Test(){}
              // 只有Test的實(shí)例可調(diào)用
              public void sayHello(){
                  System.out.println("hello");
              }
          }

          主類如下:

          import java.lang.reflect.Constructor;
          import java.lang.reflect.InvocationTargetException;

          public class Main {
              public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
                  // 獲得Test類的class實(shí)例
                  Class cTest = Test.class;
                  // 獲得Test類的構(gòu)造方法
                  Constructor constructor = cTest.getDeclaredConstructor();
                  // 設(shè)置訪問(wèn)權(quán)限,對(duì)于執(zhí)行非public的之前需先調(diào)用這個(gè)方法
                  constructor.setAccessible(true);
                  // 構(gòu)造Test實(shí)例
                  Test test = (Test) constructor.newInstance();
                  // 調(diào)用sayHello方法
                  test.sayHello();
              }
          }


          運(yùn)行結(jié)果:


          成功調(diào)用sayHello方法,即證明了我們通過(guò)反射可以實(shí)例化即使構(gòu)造方法是私有的類的實(shí)例。


          接下來(lái)再看看通過(guò)反射構(gòu)造Class類的實(shí)例會(huì)怎樣?

          可以看到再代碼14行執(zhí)行setAccessible(true)方法時(shí)就拋異常了,前面已經(jīng)說(shuō)過(guò),要想執(zhí)行非public的必須得先調(diào)用setAccessible(true)方法。點(diǎn)進(jìn)源碼看看,

          原來(lái)如此,它這里做了校驗(yàn),你要是想訪問(wèn)Class類的構(gòu)造方法,那么不好意思直接給你拋異常。Java虛擬機(jī)規(guī)范規(guī)定,所有的Class類的class實(shí)例均由JVM執(zhí)行過(guò)程中動(dòng)態(tài)加載,即在加載類時(shí),讀取定義該類的class文件(字節(jié)碼文件)創(chuàng)建class實(shí)例并放在JVM的方法區(qū)中,我們是不可能創(chuàng)建的,只能獲得。我們知道類是只會(huì)被JVM加載一次,這也說(shuō)明了類的class實(shí)例只有一個(gè),全局唯一且共享,所以不管使用什么方式獲取某個(gè)類的class實(shí)例,該class實(shí)例是相同的,使用‘’==‘’返回true。


          反射的應(yīng)用:

          Java中的對(duì)象有兩種類型,即編譯時(shí)類型和運(yùn)行時(shí)類型。編譯時(shí)類型在聲明對(duì)象時(shí)所采用的類型,運(yùn)行時(shí)類型指為對(duì)象賦值時(shí)所采用的類型。在如下代碼中,person對(duì)象的編譯時(shí)類型為Person,運(yùn)行時(shí)類型為Student,

          Person person = new Student();

          因此,程序在編譯期間無(wú)法預(yù)知該對(duì)象和類的真實(shí)信息,只能通過(guò)運(yùn)行時(shí)信息來(lái)發(fā)現(xiàn)該對(duì)象和類的真實(shí)信息,而其真實(shí)信息(對(duì)象的屬性和方法)通常通過(guò)反射機(jī)制來(lái)獲取,這便是Java語(yǔ)言的反射機(jī)制的核心功能。


          反射的API:

          Java的反射API主要用于在運(yùn)行過(guò)程中動(dòng)態(tài)生成類、接口或?qū)ο蟮刃畔?,其常用API如下:

          • Class類:用于獲取類的屬性、方法等信息。

          • Field類:表示類的成員變量,用于獲取和設(shè)置類中的屬性值

          • Method類:表示類的方法,用于獲取方法的描述信息或執(zhí)行某個(gè)方法

          • Constructor類:表示類的構(gòu)造方法

          反射的步驟:

          1、獲取想要操作的類的Class對(duì)象,該Class對(duì)象是反射的核心,通過(guò)它可以調(diào)用類的任意方法。

          2、調(diào)用Class對(duì)象所對(duì)應(yīng)的類中定義的方法,這是反射的使用階段。

          3、使用反射API來(lái)獲取并調(diào)用類的屬性和方法等信息。

          獲取Class對(duì)象的3種方法如下:

          1、調(diào)用某個(gè)對(duì)象的getClass方法以獲取該類對(duì)應(yīng)的Class對(duì)象:

          Test test = new Test();
          Class c = test.getClass();

          2、調(diào)用某個(gè)類的class屬性以獲取該類對(duì)應(yīng)的Class對(duì)象:

          Class c = Test.class;

          3、調(diào)用Class類中的forName靜態(tài)方法以獲取該類對(duì)應(yīng)的Class對(duì)象,這是最安全、性能也最好的方法:

          Class c = Class.forName("test.Test");// 包路徑加類名

          訪問(wèn)字段:

          Class類提供了以下幾個(gè)方法來(lái)獲取字段:

          • Field getField(name):根據(jù)字段名獲取某個(gè)public的field(包括父類)

          • Field getDeclaredField(name):根據(jù)字段名獲取當(dāng)前類的某個(gè)field(不包括父類)

          • Field[] getFields():獲取所有public的field(包括父類)

          • Field[] getDeclaredFields():獲取當(dāng)前類的所有field(不包括父類)


          一個(gè)Field對(duì)象包含了一個(gè)字段的所有信息:

          • String getName():返回字段名稱

          • Class getType():返回字段類型,也是一個(gè)Class實(shí)例

          • int getModifiers():返回字段的修飾符,它是一個(gè)int,不同的bit表示不同的含義

          • get(Object):返回指定對(duì)象Object的字段的值

          • set(Object, Object):設(shè)置字段的值,第一個(gè)Object參數(shù)是指定的實(shí)例,第二個(gè)Object參數(shù)是待修改的值

          訪問(wèn)方法:

          Class類提供了以下幾個(gè)方法來(lái)獲取Method:

          • Method getMethod(name, Class…):獲取某個(gè)public的Method(包括父類)

          • Method getDeclaredMethod(name, Class…):獲取當(dāng)前類的某個(gè)Method(不包括父類)

          • Method[] getMethods():獲取所有public的Method(包括父類)

          • Method[] getDeclaredMethods():獲取當(dāng)前類的所有Method(不包括父類)


          一個(gè)Method對(duì)象包含一個(gè)方法的所有信息:

          • String getName():返回方法名稱

          • Class getReturnType():返回方法返回值類型,也是一個(gè)Class實(shí)例

          • Class[] getParameterTypes():返回方法的參數(shù)類型,是一個(gè)Class數(shù)組

          • int getModifiers():返回方法的修飾符,它是一個(gè)int,不同的bit表示不同的含義

          • Object invoke(Object instance, Object… parameters):調(diào)用某個(gè)對(duì)象的方法


          訪問(wèn)構(gòu)造方法:

          通過(guò)Class實(shí)例獲取Constructor的方法如下:

          • getConstructor(Class…):獲取某個(gè)public的Constructor

          • getDeclaredConstructor(Class…):獲取某個(gè)Constructor

          • getConstructors():獲取所有public的Constructor

          • getDeclaredConstructors():獲取所有Constructor


          創(chuàng)建對(duì)象的兩種方式:

          1、使用Class對(duì)象的newInstance方法創(chuàng)建該Class對(duì)象對(duì)應(yīng)類的實(shí)例,這種方法要求該Class對(duì)象對(duì)應(yīng)的類有默認(rèn)的空構(gòu)造器。

          Class c = Test.class;
          Test test = (Test) c.newInstance();

          2、先使用Class對(duì)象獲取指定的Constructor對(duì)象,再調(diào)用Constructor對(duì)象的newInstance方法創(chuàng)建Class對(duì)象對(duì)應(yīng)類的實(shí)例,通過(guò)這種方法可以選定構(gòu)造方法創(chuàng)建實(shí)例。

          // 獲取構(gòu)造方法Integer(int):
          Constructor cons = Integer.class.getConstructor(int.class);
          // 調(diào)用構(gòu)造方法:
          Integer n1 = (Integer) cons.newInstance(123);

          注意:

          調(diào)用非public的方法時(shí),必須首先通過(guò)setAccessible(true)設(shè)置允許訪問(wèn)。setAccessible(true)可能會(huì)失敗。


          至此,Java的反射機(jī)制介紹到這里

          ————————————————

          版權(quán)聲明:本文為CSDN博主「b17a」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。

          原文鏈接:

          https://blog.csdn.net/weixin_45685353/article/details/115425373





          粉絲福利:Java從入門(mén)到入土學(xué)習(xí)路線圖

          ??????

          ??長(zhǎng)按上方微信二維碼 2 秒


          感謝點(diǎn)贊支持下哈 

          瀏覽 42
          點(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>
                  最新在线无码热a | 大香蕉在线精品视频 | aicaobiwang | 爽死777 | 97自拍偷拍视频 |