反射

什么是反射?

Java反射機制是在運行狀態(tài)中姿骏,對于任意一個類身笤,都能夠知道這個類的所有屬性和方法豹悬;對于任意一個對象,都能夠調(diào)用它的任意一個方法和屬性液荸;這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法的功能稱為Java語言的反射機制瞻佛。

簡單的來說:
1.通過new關(guān)鍵字創(chuàng)建對象操作對象,在編譯時就已經(jīng)確定。
2.通過反射可以在程序運行過程中動態(tài)的操作對象伤柄,可以獲得編譯期無法獲得的信息绊困,動態(tài)操作最大限度發(fā)揮了java擴展性。

反射是框架的靈魂适刀,它可以有效地降低類之間的耦合秤朗,很多框架都運用了反射原理,例如hibernate 的實體類笔喉,Spring 的 AOP等等都有反射的實現(xiàn)

反射的具體實現(xiàn)

想要實現(xiàn)反射取视,就必須先拿到該類的字節(jié)碼文件對象(.class),通過字節(jié)碼文件對象,就能夠通過該類中的方法獲取到我們想要的所有信息常挚,每一個類對應(yīng)著一個字節(jié)碼文件也就對應(yīng)著一個Class類型的對象作谭,也就是字節(jié)碼文件對象.

1. 獲取字節(jié)碼文件對象(Class)的三種方式

   /**
     * 方式一:
     * Object中的getClass方法來獲取Class對象
     * 使用這方式必須有具體的類,并創(chuàng)建對象待侵。
     * 這種方式使用的少丢早,一般是傳的是Object,不知道類型的時候才使用秧倾。
     */
            Object obj=new Proson();
            Class clazz1 =obj.getClass();
            System.err.println("通過getClass():"+clazz1);


   /**
     * 方式二:
     * 直接通過 類名.class來獲取Class對象怨酝。
     * 任何類型中都具有隱含的靜態(tài)成員變量class,使用簡單,但是擴展性還是不足那先。
     */
            Class clazz2=Proson.class;
            System.err.println("通過類名.class:"+clazz2);


  /**
     * 方式三:
     * 通過Class 對象的forName()靜態(tài)方法來獲取Class對象农猬。
     * 使用最多叶摄,通過類的全限定名看铆,但可能拋出ClassNotFoundException異常
     */
          Class clazz3 = Class.forName("com.xiaoli.bean.Proson");
          System.err.println("通過類的全限定名:"+clazz3);

         //比較三種方法對象是否是相同實例。
           System.err.println(clazz1==clazz2);
           System.err.println(clazz1==clazz3);
           System.err.println(clazz2==clazz3);

運行結(jié)果得知

三種方法都可以獲取字節(jié)碼文件對象阿纤。
一個類在 JVM 中只會有一個 Class 實例(比較之后全為true)


image.png

2. 創(chuàng)建對象的方式揖闸。

Proson類

 public class Proson {
    //私有屬性
    private String name;
    //公有屬性
    public  Integer age;
    //無參構(gòu)造
    public Proson() {
    }
    //有參構(gòu)造
    public Proson(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    //私有方法
     private void method1(){
        System.err.println("method1——run");
    }
    //公有方法
    public void method2(String param){
        System.err.println("method1=2——run :"+param);
    }


    @Override
    public String toString() {
        return "Proson{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

實例化對象的方式
通過new關(guān)鍵字與反射相互對比加深對反射的認識揍堕,詳解代碼如下:

     // 不用反射: 創(chuàng)建對象,需要手動new對象不能動態(tài)創(chuàng)建汤纸。
     // new的時候根據(jù)new的類名尋找字節(jié)碼文件衩茸,加載進入內(nèi)存,創(chuàng)建Class對象贮泞,并接著創(chuàng)建對應(yīng)的Proson對象楞慈。
         Proson p=new Proson();

        //通過反射:只需要一個名字,就可以創(chuàng)建對象啃擦。
        String className="com.xiaoli.bean.Proson";
        //尋找該名稱的類文件囊蓝,加載進內(nèi)存,并創(chuàng)建Class對象令蛉。
        Class clazz = Class.forName(className);
        //通過Class對象的newInstance()創(chuàng)建類對象聚霜。
        Object o = clazz.newInstance();



調(diào)用有參構(gòu)造方法初始化變量
通過有參構(gòu)造對比反射,詳解代碼如下:

        //不用反射:通過構(gòu)造方法實例化并初始化變量
        Object obj1=new Proson("name",18);
        System.err.println("不用反射: "+obj1);
        //通過反射:Class對象的getConstructor方法拿到構(gòu)造器。
        Constructor constructor = clazz.getConstructor(String.class, Integer.class);
        //通過構(gòu)造器的newInstance方法實例化并初始化變量
        Object obj2=constructor.newInstance("name2",22);
        System.err.println("通過反射: "+obj2);

得到結(jié)果


在這里插入圖片描述

Class 類中方法詳解

到這里應(yīng)該理解到Class對反射的重要性了吧俯萎?那么Class類中有什么常用方法呢傲宜?

獲取公共構(gòu)造器 getConstructors()
獲取所有構(gòu)造器 getDeclaredConstructors()
獲取該類對象 newInstance()
獲取類名包含包路徑 getName()
獲取類名不包含包路徑 getSimpleName()
獲取類公共類型的所有屬性 getFields()
獲取類的所有屬性 getDeclaredFields()
獲取類公共類型的指定屬性 getField(String name)
獲取類全部類型的指定屬性 getDeclaredField(String name)
獲取類公共類型的方法 getMethods()
獲取類的所有方法 getDeclaredMethods()
獲得類的特定公共類型方法: getMethod(String name, Class[] parameterTypes)
獲取內(nèi)部類 getDeclaredClasses()
獲取外部類 getDeclaringClass()
獲取修飾符 getModifiers()
獲取所在包 getPackage()
獲取所實現(xiàn)的接口 getInterfaces()

通過一些例子來演示以上常用方法,詳解代碼如下夫啊。

       //這里方便操作演示用第二種發(fā)方法獲取字節(jié)碼對象
        Class clazz2=Proson.class;
        //通過反射調(diào)用有參構(gòu)造函數(shù)初始化對象(上面演示過) 
        Constructor constructor = clazz2.getConstructor(String.class, Integer.class);
        Object obj = constructor.newInstance("lixiaoli", 18);

       //獲得類完整的名字
        String className1 = clazz2.getName();
        System.err.println("1類完整的名字: "+className1);

       //獲得類名不包含包路徑
        String className2 = clazz2.getSimpleName();
        System.err.println("2類名不含路徑: "+className2);

        //獲得類中公共類型(public)屬性
        Field[] fields = clazz2.getFields();
        String fieldName="";
        for(Field field : fields){
            fieldName+=field.getName()+"  ";
        }
        System.err.println("3類中公共屬性: "+fieldName);

        //獲得類中全部類型(包括私有)屬性
        Field[] fieldsAll = clazz2.getDeclaredFields();
        fieldName="";
        for(Field field : fieldsAll){
            fieldName+=field.getName()+"  ";
        }
        System.err.println("4類中全部屬性: "+fieldName);

        //獲得公共指定屬性值
        Field age = clazz2.getField("age");
        Object o = age.get(obj);
        System.err.println("5公共指定屬性: "+o);

        //獲得私有指定屬性值
        Field name = clazz2.getDeclaredField("name");
        // Field name = clazz2.getField("name");只能獲取共有屬性 故此方法會拋出NoSuchFieldException異常,所以選用getDeclaredField();
        name.setAccessible(true); //設(shè)置為true才能獲取私有屬性
        Object o2 = name.get(obj);
        System.err.println("6類中私有指定屬性值: "+o2);

        //獲取類所有公共類型方法   這里包括 Object 類的一些方法
        Method[] methods = clazz2.getMethods();
        String methodsName="";
        for(Method method : methods){
            methodsName+=method.getName()+"  ";
        }
        System.err.println("7類公共類型方法: "+methodsName);

        //獲取該類中的所有方法(包括私有)
        Method[] methodsAll = clazz2.getDeclaredMethods();
        methodsName="";
        for(Method method : methodsAll){
            methodsName+=method.getName()+"  ";
        }
        System.err.println("8類中的所有方法: "+methodsName);

        //獲取并使用指定方法
        Method method1 = clazz2.getDeclaredMethod("method1");//獲取無參私有方法
        method1.setAccessible(true);//設(shè)置為true才能獲取私有方法
        method1.invoke(obj);//調(diào)用無參方法

        Method method2 = clazz2.getMethod("method2",String.class);//獲取有參數(shù)方法
        method2.invoke(obj,"666");//調(diào)用有參方法


運行結(jié)果


image.png

反射總結(jié)

熟練的使用反射能讓我們的程序耦合度降低函卒,當(dāng)然會損失一部分性能,畢竟有失才有得撇眯。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末报嵌,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子熊榛,更是在濱河造成了極大的恐慌锚国,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件玄坦,死亡現(xiàn)場離奇詭異血筑,居然都是意外死亡,警方通過查閱死者的電腦和手機煎楣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門豺总,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人择懂,你說我怎么就攤上這事喻喳。” “怎么了困曙?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵表伦,是天一觀的道長。 經(jīng)常有香客問我慷丽,道長蹦哼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任要糊,我火速辦了婚禮翔怎,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘杨耙。我一直安慰自己,他們只是感情好飘痛,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布珊膜。 她就那樣靜靜地躺著,像睡著了一般宣脉。 火紅的嫁衣襯著肌膚如雪车柠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天,我揣著相機與錄音竹祷,去河邊找鬼谈跛。 笑死,一個胖子當(dāng)著我的面吹牛塑陵,可吹牛的內(nèi)容都是我干的感憾。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼令花,長吁一口氣:“原來是場噩夢啊……” “哼阻桅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起兼都,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤嫂沉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后扮碧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體趟章,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年慎王,在試婚紗的時候發(fā)現(xiàn)自己被綠了蚓土。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡柬祠,死狀恐怖北戏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情漫蛔,我是刑警寧澤嗜愈,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站莽龟,受9級特大地震影響蠕嫁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜毯盈,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一剃毒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧搂赋,春花似錦赘阀、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至宋欺,卻和暖如春轰豆,著一層夾襖步出監(jiān)牢的瞬間胰伍,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工酸休, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留骂租,地道東北人。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓斑司,卻偏偏與公主長得像渗饮,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子陡厘,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容

  • 課程地址:Java基礎(chǔ)之 — 反射(非常重要) (使用的前提條件:必須先得到代表的字節(jié)碼的Class抽米,Cla...
    叨唧唧的閱讀 683評論 0 2
  • (轉(zhuǎn)自csdn) 反射是框架設(shè)計的靈魂 (使用的前提條件:必須先得到代表的字節(jié)碼的Class,Class類用于表示...
    尼爾君閱讀 225評論 0 1
  • 整體Retrofit內(nèi)容如下: 1糙置、Retrofit解析1之前哨站——理解RESTful 2云茸、Retrofit解析...
    隔壁老李頭閱讀 4,566評論 2 12
  • 一、概述 Java反射機制定義 Java反射機制是在運行狀態(tài)中谤饭,對于任意一個類标捺,都能夠知道這個類中的所有屬性和方法...
    CoderZS閱讀 1,632評論 0 26
  • 反射庫提供了一個非常豐富且精心設(shè)計的工具集,以便能夠動態(tài)編寫能夠操縱Java代碼的程序揉抵。這項功能被大量應(yīng)用于Jav...
    Steven1997閱讀 620評論 0 2