花一杯茶的時間,學(xué)會Java反射(基礎(chǔ)篇)

什么是java反射

JAVA 反射機制是在運行狀態(tài)中之众,對于任意一個類,都能夠知道這個類的所有屬性和方法棺禾;對于任意一個對象,都能夠調(diào)用它的任意一個方法和屬性;這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法的功能稱為 java 語言的反射機制袍患。

其實就是指我們可以在運行時加載、探知诡延、使用編譯期間完全未知的 classes。

java反射的作用

1.反射可以更好的對代碼進行自審肆良。相當(dāng)于程序員的一面鏡子;
2.反射可以解耦惹恃,提高代碼的擴展性。如工廠模式巫糙。
3.為滿足需求,獲取某代碼進行部分修改或者破解参淹;
4.方便多人開發(fā)醉锄。
假如有多個程序員開發(fā)同個項目,A程序員需要用到B程序員所寫的類浙值,若B程序員并沒有完成他所寫的類恳不,那么A程序員是不能通過編譯的。此時开呐,反射就能很好的解決該問題烟勋;

學(xué)習(xí)反射

  • 獲得完整的包名和類名

有三種方式。不過一般都是使用第一種筐付,通過包名+類名獲取需要的類卵惦,擴展性好很多:

    package com.demo;

    public class ReflectionDemo {

        public static void main(String[] args) {
            try {
                //第一種(推薦使用)
                Class<?> cls1 = Class.forName("com.demo.Person");
                System.out.println(cls1.getName());
                
                // 第二種
                Person per = new Person();
                Class<?> cls2 = per.getClass();
                System.out.println(cls2.getName());
                
                // 第三種
                Class<?> cls3 = Person.class;
                System.out.println(cls3.getName());
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

    class Person {}

打印結(jié)果
com.demo.Person
com.demo.Person
com.demo.Person

<br />

  • 反射進行類的實例化并獲取構(gòu)造方法

根據(jù)構(gòu)造方法是否有參數(shù),參數(shù)的類型有關(guān)家妆。

    package com.demo;

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

    public class ReflectionDemo {

        public static void main(String[] args) {
            try {
                // 獲取類
                Class<?> cls1 = Class.forName("com.demo.Person");

                // 直接獲取實例(ps:需要獲取的類中有無參構(gòu)造方法,并且該構(gòu)造方法不能是private的)
                Person person = (Person) cls1.newInstance();
                System.out.println("[ 直接獲取實例 ]person.print() :" + person.print());

                System.out.println("-----------------");

                // 獲取全部構(gòu)造方法
                Constructor<?>[] con = cls1.getConstructors();
                for (int i = 0; i < con.length; i++) {
                    System.out.println("[ 獲取全部構(gòu)造方法 ]constructor[" + i + "] :" + con[i].toString());
                }
                
                System.out.println("-----------------");

                // 通過帶參數(shù)的構(gòu)造方法獲取實例(對應(yīng)上面顯示的構(gòu)造方法順序)
                Person per1 = (Person) con[1].newInstance("maxchan");
                System.out.println("[ 獲取帶參數(shù)的構(gòu)造方法實例 ] : name:" + per1.getName());
                Person per2 = (Person) con[2].newInstance("maxchan", "男");
                System.out.println("[ 獲取帶參數(shù)的構(gòu)造方法實例 ] : name:" + per2.getName() + " sex:" + per2.getSex());
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }

    class Person {
        private String name; // 姓名
        private String sex; // 性別

        public Person() {
        }

        public Person(String name) {
            this.name = name;
        }

        public Person(String name, String sex) {
            this.name = name;
            this.sex = sex;
        }

        public String getName() {
            return name;
        }

        public String getSex() {
            return sex;
        }

        public String print() {
            return "print";
        }
    }

運行結(jié)果:

    [ 直接獲取實例 ]person.print() :print
    -----------------
    [ 獲取全部構(gòu)造方法 ]constructor[0] :public com.demo.Person()
    [ 獲取全部構(gòu)造方法 ]constructor[1] :public com.demo.Person(java.lang.String)
    [ 獲取全部構(gòu)造方法 ]constructor[2] :public com.demo.Person(java.lang.String,java.lang.String)
    -----------------
    [ 獲取帶參數(shù)的構(gòu)造方法實例 ] : name:maxchan
    [ 獲取帶參數(shù)的構(gòu)造方法實例 ] : name:maxchan sex:男

<br />

  • 查看類的方法

查看類有什么方法鸵荠,可以使用getMethods()getDeclaredMethods()
不同的是getMethods()只能獲取該類以及父類使用public修飾的方法伤极;getDeclaredMethods()獲取的是此類的所有方法蛹找,沒有獲取父類的方法。
若要查看某個父類中的所有方法哨坪,可以通過類cls1.getSuperclass()先獲取該父類庸疾,再調(diào)用getDeclaredMethods()方法。

    package com.demo;

    import java.lang.reflect.Method;

    public class ReflectionDemo {

        public static void main(String[] args) {
            try {
                // 獲取類
                Class<?> cls1 = Class.forName("com.demo.Person");
                // 獲取方法(只有使用public修飾符的方法)
                Method[] method = cls1.getMethods();
                for (int i = 0; i < method.length; i++) {
                    System.out.println("method[" + i + "] :" + method[i]);
                }
                
                System.out.println("--------------------------");
                
                //獲取全部方法(使用缺省当编、pulbic届慈、private、protected修飾的方法)
                Method[] method_all = cls1.getDeclaredMethods();
                for (int i = 0; i < method_all.length; i++) {
                    System.out.println("method_all[" + i + "] :" + method_all[i]);
                }

            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

    class Person {
        String defaultString() {
            return "defaultString";
        }

        private String privateString() {
            return "privateString";
        }

        protected String protectedString() {
            return "protectedString";
        }

        public String publicString() {
            return "person";
        }
    }

打印結(jié)果

    method[0] :public java.lang.String com.demo.Person.publicString()
    method[1] :public final void java.lang.Object.wait() throws java.lang.InterruptedException
    method[2] :public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
    method[3] :public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
    method[4] :public boolean java.lang.Object.equals(java.lang.Object)
    method[5] :public java.lang.String java.lang.Object.toString()
    method[6] :public native int java.lang.Object.hashCode()
    method[7] :public final native java.lang.Class java.lang.Object.getClass()
    method[8] :public final native void java.lang.Object.notify()
    method[9] :public final native void java.lang.Object.notifyAll()
    --------------------------
    method_all[0] :java.lang.String com.demo.Person.defaultString()
    method_all[1] :private java.lang.String com.demo.Person.privateString()
    method_all[2] :protected java.lang.String com.demo.Person.protectedString()
    method_all[3] :public java.lang.String com.demo.Person.publicString()

<br />

  • 獲取類的某個具體方法

和上面相同,若只需獲取public方法金顿,用getMethod([具體的方法名],[參數(shù)類型])臊泌;若需要獲取使用其它修飾符的方法,則需使用getDeclaredMethod([具體的方法名],[參數(shù)類型])

    package com.demo;

    import java.lang.reflect.Method;

    public class ReflectionDemo {

        public static void main(String[] args) {
            try {
                // 獲取類
                Class<?> cls1 = Class.forName("com.demo.Person");

                // 獲取類的某個具體的方法
                Method method = cls1.getMethod("publicString");
                System.out.println("method.getName() :" + method.getName());
                
                System.out.println("--------------------------");

                // 獲取類的某個具體的方法
                Method declared_method = cls1.getDeclaredMethod("privateString");
                System.out.println("declared_method.getName() :" + declared_method.getName());
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
    }

    class Person {
        String defaultString() {
            return "defaultString";
        }

        private String privateString() {
            return "privateString";
        }

        protected String protectedString() {
            return "protectedString";
        }

        public String publicString() {
            return "person";
        }
    }

打印結(jié)果:
method.getName() :publicString
--------------------------
declared_method.getName() :privateString
<br />

  • 調(diào)用類的方法
    package com.demo;

    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;

    public class ReflectionDemo {

        public static void main(String[] args) {
            try {
                // 獲取類
                Class<?> cls1 = Class.forName("com.demo.Person");
                Person per = (Person) cls1.newInstance();

                // 調(diào)用帶參數(shù)的方法(第一個參數(shù)使用方法名渠概,后面的參數(shù)是對應(yīng)的參數(shù)類型播揪,若有多個參數(shù)則顯示多個參數(shù)類型猪狈,若無參數(shù)辩恼,則不顯示)
                //invoke方法的第一個參數(shù)是類的實例
                Method param_method = cls1.getMethod("setContent", String.class);
                param_method.invoke(per, "content");

                // 調(diào)用不帶參數(shù)的方法獲取數(shù)據(jù)
                Method method = cls1.getMethod("getContent");
                String result = (String) method.invoke(per);
                System.out.println("[ 調(diào)用不帶參數(shù)的方法獲取數(shù)據(jù) ] :" + result);

                // 調(diào)用不帶參數(shù)的靜態(tài)方法獲取數(shù)據(jù)(只需將invoke方法的第一個參數(shù)改成null即可)
                Method static_method = cls1.getMethod("getStaticContent");
                String static_result = (String) static_method.invoke(null);
                System.out.println("[ 調(diào)用不帶參數(shù)的靜態(tài)方法獲取數(shù)據(jù) ] :" + static_result);

            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
    }

    class Person {
        public String content;

        public String getContent() {
            return content;
        }

        public void setContent(String content) {
            this.content = content;
        }

        public static String getStaticContent() {
            return "static content";
        }

    }

運行結(jié)果:

    [ 調(diào)用不帶參數(shù)的方法獲取數(shù)據(jù) ] :content
    [ 調(diào)用不帶參數(shù)的靜態(tài)方法獲取數(shù)據(jù) ] :static content

<br />

  • 變量的獲取和變量值的設(shè)置

變量的獲取使用Field状共,跟Method的用法很像。有getFields()以及getDeclaredFields()冯袍。getDeclaredFields()可以獲取全部變量康愤,getFields()只能獲取用public修飾的變量。

    package com.demo;

    import java.lang.reflect.Field;

    public class ReflectionDemo {

        public static void main(String[] args) {
            try {
                // 獲取類
                Class<?> cls1 = Class.forName("com.demo.Person");

                // 獲取public修飾的變量
                Field[] field = cls1.getFields();
                for (Field f : field) {
                    System.out.println("[ 獲取public修飾的變量 ] (getFields):" + f.getName());
                }

                System.out.println("-----------------------------");

                // 獲取全部的變量
                Field[] declared_field = cls1.getDeclaredFields();
                for (Field f : declared_field) {
                    System.out.println("[ 獲取全部的變量 ] (declared_field):" + f.getName());
                }

                System.out.println("-----------------------------");

                // 通過變量名,設(shè)置或獲取變量值
                Person person = (Person) cls1.newInstance();
                Field field1 = cls1.getDeclaredField("sex");
                System.out.println("[ 獲取變量名 ] :" + field1.get(person));

                // 設(shè)置變量值
                field1.set(person, "女");
                System.out.println("[ 設(shè)置變量名 ] :" + field1.get(person));

            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
    }

    class Person {
        private String name; // 姓名
        public String sex = "男"; // 性別
    }

運行結(jié)果:

    [ 獲取public修飾的變量 ] (getFields):sex
    -----------------------------
    [ 獲取全部的變量 ] (declared_field):name
    [ 獲取全部的變量 ] (declared_field):sex
    -----------------------------
    [ 獲取變量名 ] :男
    [ 設(shè)置變量名 ] :女

這些是反射比較常用的方法肴捉。在花一杯茶的時間齿穗,學(xué)會Java反射(實用篇)中饺律,我會寫出一些用到反射的例子。大家若有什么疑問或意見脖卖,請在評論提出,謝謝畦木。若有錯誤或者新的內(nèi)容,我都會修改此貼攻锰。代碼多了點妓雾,但是注釋寫的很清楚了。感謝大家的觀看妒蛇。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末绣夺,一起剝皮案震驚了整個濱河市陶耍,隨后出現(xiàn)的幾起案子她混,更是在濱河造成了極大的恐慌坤按,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件酗钞,死亡現(xiàn)場離奇詭異砚作,居然都是意外死亡偎巢,警方通過查閱死者的電腦和手機兼耀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來窍霞,“玉大人但金,你說我怎么就攤上這事±淅#” “怎么了似枕?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵凿歼,是天一觀的道長。 經(jīng)常有香客問我味赃,道長心俗,這世上最難降的妖魔是什么蓉驹? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任戒幔,我火速辦了婚禮诗茎,結(jié)果婚禮上敢订,老公的妹妹穿的比我還像新娘罢吃。我一直安慰自己,他們只是感情好矾柜,可當(dāng)我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布怪蔑。 她就那樣靜靜地躺著,像睡著了一般喧枷。 火紅的嫁衣襯著肌膚如雪弓坞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天戚扳,我揣著相機與錄音,去河邊找鬼菩帝。 笑死,一個胖子當(dāng)著我的面吹牛呼奢,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播握础,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼简烘!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起孤澎,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤欠窒,失蹤者是張志新(化名)和其女友劉穎岖妄,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體荐虐,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡福扬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了向拆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片酪耳。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡碗暗,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出晴圾,到底是詐尸還是另有隱情噪奄,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站碰缔,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏瀑焦。R本人自食惡果不足惜梗肝,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一巫击、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦驻右、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至菊匿,卻和暖如春计福,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背佩厚。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工抄瓦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留陶冷,地道東北人。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓摸恍,卻偏偏與公主長得像立镶,于是被迫代替她去往敵國和親类早。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,779評論 2 354

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

  • 一:java概述:1,JDK:Java Development Kit逆日,java的開發(fā)和運行環(huán)境,java的開發(fā)工...
    ZaneInTheSun閱讀 2,650評論 0 11
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,111評論 25 707
  • 從三月份找實習(xí)到現(xiàn)在,面了一些公司坪圾,掛了不少惑朦,但最終還是拿到小米漾月、百度胃珍、阿里、京東栈雳、新浪缔莲、CVTE、樂視家的研發(fā)崗...
    時芥藍閱讀 42,246評論 11 349
  • “我為我狂妄負責(zé)的方式蛀骇,就是我活的精致擅憔¢茉危” 瘋子是一個狂妄的人,她炒老板魷魚辟灰,紋身,打耳洞西采,穿潮款衣服继控,83年的這...
    20a43a3c7a74閱讀 5,607評論 103 196
  • 到深圳的第26天武通,沒想到我已經(jīng)到深圳快一個月了。 然而一直到今天為止冶忱,我才算真正的搬完家。將以前在貴陽呆了六年多的...
    明見蘇Karen閱讀 704評論 0 50