進擊的Android工程師之Java基礎: 反射

反射機制呢就是在程序運行時旗们,動態(tài)的獲取類(class),類的方法(method)屬性(field)等。主要的注意點就是程序運行時動態(tài)的獲取。
這里主要是從代碼的角度來講解Java反射坝锰。在使用中我們用的較多的幾個類有ClassMethod重付,Field顷级,Constructor,Annotation等。
下面我們分別介紹下确垫。

獲取Class

獲取class對象有如下三種方式:

  • cat.getClass
  • Cat.class
  • Class.forName("xyz.magicer.Cat")
        //方式1 調用對象的getClass()方式弓颈,該方法屬于Object類
        Class<? extends Cat> aClass = cat.getClass();
        //方式2 直接類.class獲取。
        Class<Cat> catClass = Cat.class;
        //方式3 通過Class類的靜態(tài)方法forName獲取删掀,參數為想要獲取的類的全名(含包名翔冀,不然會報ClassNotFoundException)
        try {
            Class<?> cat2 = Class.forName("xyz.magicer.Cat");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

在使用中根據實際情況選擇,獲取Class對象是我們使用反射的第一步披泪。不過還是很簡單的纤子。獲取了Class對象后,怎么創(chuàng)建一個實體呢款票?catClass.newInstance()
不過改方法會拋出兩個異常:InstantiationExceptionIllegalAccessException

  • InstantiationException :當該Class不能被實例化的時候拋出該異常控硼,例如,為抽象類艾少、接口卡乾、數組類、基本類缚够、Void等時幔妨。
  • IllegalAccessException:當無參構造為私有時
    還有一種創(chuàng)建實體的方式是使用Constructor,在下邊在介紹潮瓶。

Method

獲取Method

類或接口的方法對應這Method這個類。我們通過Class對象來獲取钙姊。主要方法有

  • getMethods(): 返回Method[] 返回所有public的方法毯辅。包含父類或父接口的方法。
  • getDeclaredMethods(): 返回Method[] 返回所有的方法煞额。包括 private public defaultprotected的思恐。不包含父類或父接口的方法
  • getMethod(String name, Class<?>... parameterTypes) : 返回Method, 根據方法名和類型獲取Method膊毁。類或接口的及父類父接口公共成員方法胀莹。
  • getDeclaredMethod(String name, Class<?>... parameterTypes): 返回Method。根據方法名和類型返回Method婚温。類和接口的所有方法描焰。
        //sleep是private的
        Method[] methods = catClass.getMethods();
        for (Method method : methods) {
            //method.getName() 返回方法名,不包括修飾符,參數和返回值荆秦。
            System.out.printf(method.getName()+" ");
        } 
        // 打印toString getName setName setColor eat eat getAge setAge getColor wait wait wait equals hashCode getClass notify notifyAll 

        System.out.println();

        Method[] declaredMethods = catClass.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.printf(declaredMethod.getName()+" ");
        } 
        //打印 toString getName setName sleep setColor eat eat getAge setAge getColor 

        //拋出NoSuchMethodException 因為sleep的訪問權限為private
       //Method sleep1 = catClass.getMethod("sleep", null);
        Method hashCode = catClass.getMethod("hashCode", null);
        //拋出NoSuchMethodException篱竭,因為hashCode是父類的方法。
       //Method hashCode1 = catClass.getDeclaredMethod("hashCode", null);
        Method eat2 = catClass.getMethod("eat",null);
        Method sleep1 = catClass.getDeclaredMethod("sleep", null);

通過上面的代碼我們能看到步绸,getMethods()可以獲取父類的方法掺逼,但是不能獲取私有方法,而getDeclaredMethod()方法不可以獲取父類的方法瓤介,但是可以獲取私有的方法吕喘。getMethod也是一樣,可以獲取父類父接口方法刑桑,但是無法獲取私有方法氯质,而getDeclaredMethod可以獲取私有方法不能獲取父類父接口方法。
而帶s和不帶s的區(qū)別是帶s返回值為Method[]漾月,不帶返回的是Method病梢。

調用Method

既然我們獲取到了方法(Method)當然是想調用它,那么怎么調用呢梁肿?Method有個方法invoke(Object obj, Object... args).
invoke接收兩個參數蜓陌,第一個是調用該方法的實體,第二個是方法的參數吩蔑。參數類型多個時順序要跟方法參數相同钮热。

        Method eat1 = catClass.getMethod("eat");
        eat1.invoke(catInstance,null); //打印:我只吃小魚干烛芬。
        Method eat = catClass.getDeclaredMethod("eat");
        eat.invoke(catInstance,null);  //打铀砥凇: 我只吃小魚干。

        Method sleep = catClass.getDeclaredMethod("sleep");
        //IllegalAccessException
        sleep.invoke(catInstance,null);

我們會發(fā)現當私有方法invoke調用時會拋出IllegalAccessException赘娄,不是可以獲取么為什么不能調用仆潮?因為方法有權限修飾符,我們需要設置成我們可以調用的遣臼。如下:

        sleep.setAccessible(true);
        sleep.invoke(catInstance,null);

在調用前設置為可以調用就解決了性置。
在前面我們接觸到了兩個Method類的方法了(getName,和invoke)揍堰。

Method常用方法

  • getModifiers(): 返回方法修飾符
  • getAnnotations(): 可以獲取父類的注解
  • getDeclaredAnnotations(): 不可以返回父類的注解
  • getAnnotation(Class<T> annotationClass)
  • getDeclaredAnnotation(Class<T> annotationClass)
  • getParameters(): 返回Parameter[] (java1.8加入)

Field

獲取Field對象的方式跟Method一樣鹏浅,用法和規(guī)律都一樣。無非是現在方法改為getFields()屏歹、getDeclaredFields()隐砸、getField(String)、getDeclaredField(String)蝙眶。

設置Field

可以通過set方法來設置值 public void set(Object obj, Object value) 每種基本數據類型都有的setxxx()方法季希。

        //name 為私有
        Field name = catClass.getDeclaredField("name");
        name.setAccessible(true);
        name.set(cat,"啦啦啦");
        System.out.println("\n"+cat.toString());

在使用反射設置屬性的時候一定要注意,可能在代碼中用到該屬性的地方較多,改變了值之后引起一些意想不到的效果胖眷。

Constructor

獲取Constructor對象的方式跟Field和Method一樣武通。有四個方法:
getConstructors(),getDeclaredConstructors珊搀,getConstructor(Class<?>... parameterTypes)冶忱, getDeclaredConstructor(Class<?>... parameterTypes)。

得到了Constructor對象后我們就可以調用newInstance(Object ... initargs)方法進行初始化了境析,注意參數的順序囚枪。

        Constructor<Cat> constructor1 = catClass.getDeclaredConstructor(String.class, int.class, String.class);
        Cat cat1 = constructor1.newInstance("喵喵2", 3, "white");
        System.out.println(cat1.toString());

到這里我們看到,通過反射創(chuàng)建一個對象有兩種方式:(1)class.newInstance()和(2)consturctor.newInstance(Object ... initargs)劳淆。那么他們有什么區(qū)別呢链沼?
方式(1)只能調用無參構造創(chuàng)建對象,并且無參構造不能為私有沛鸵,而方式(2)可以調用所有

        Constructor<Cat> constructor1 = catClass.getDeclaredConstructor(String.class, int.class, String.class);
        Cat cat1 = constructor1.newInstance("喵喵2", 3, "white");
        System.out.println(cat1.toString());

        //調用私有構造
        Constructor<Cat> constructor2 = catClass.getDeclaredConstructor(String.class);
        constructor2.setAccessible(true);
        Cat miaomiao = constructor2.newInstance("miaomiao");
        System.out.println(miaomiao.toString());
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末括勺,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子曲掰,更是在濱河造成了極大的恐慌疾捍,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件栏妖,死亡現場離奇詭異乱豆,居然都是意外死亡,警方通過查閱死者的電腦和手機吊趾,發(fā)現死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門宛裕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人论泛,你說我怎么就攤上這事揩尸。” “怎么了屁奏?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵岩榆,是天一觀的道長。 經常有香客問我了袁,道長朗恳,這世上最難降的妖魔是什么湿颅? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任载绿,我火速辦了婚禮,結果婚禮上油航,老公的妹妹穿的比我還像新娘崭庸。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布怕享。 她就那樣靜靜地躺著执赡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪函筋。 梳的紋絲不亂的頭發(fā)上沙合,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天,我揣著相機與錄音跌帐,去河邊找鬼首懈。 笑死,一個胖子當著我的面吹牛谨敛,可吹牛的內容都是我干的究履。 我是一名探鬼主播,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼脸狸,長吁一口氣:“原來是場噩夢啊……” “哼最仑!你這毒婦竟也來了?” 一聲冷哼從身側響起炊甲,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤泥彤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蜜葱,有當地人在樹林里發(fā)現了一具尸體全景,經...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年牵囤,在試婚紗的時候發(fā)現自己被綠了爸黄。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡揭鳞,死狀恐怖炕贵,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情野崇,我是刑警寧澤称开,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站乓梨,受9級特大地震影響鳖轰,放射性物質發(fā)生泄漏。R本人自食惡果不足惜扶镀,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一蕴侣、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧臭觉,春花似錦昆雀、人聲如沸辱志。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽揩懒。三九已至,卻和暖如春挽封,著一層夾襖步出監(jiān)牢的瞬間已球,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工辅愿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留和悦,地道東北人。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓渠缕,卻偏偏與公主長得像鸽素,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子亦鳞,可洞房花燭夜當晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理馍忽,服務發(fā)現,斷路器燕差,智...
    卡卡羅2017閱讀 134,672評論 18 139
  • 一:java概述: 1遭笋,JDK:Java Development Kit,java的開發(fā)和運行環(huán)境徒探,java的開發(fā)...
    慕容小偉閱讀 1,792評論 0 10
  • 一:java概述:1瓦呼,JDK:Java Development Kit,java的開發(fā)和運行環(huán)境测暗,java的開發(fā)工...
    ZaneInTheSun閱讀 2,654評論 0 11
  • Scala與Java的關系 Scala與Java的關系是非常緊密的Q氪! 因為Scala是基于Java虛擬機碗啄,也就是...
    燈火gg閱讀 3,446評論 1 24
  • 當你老了质和。 白發(fā)蒼蒼。 坐在椅子上休息稚字。 回憶過去饲宿。 的點點滴滴的往事 是否是種幸福 回憶過去的酸甜苦辣 現在想起...
    迷之尷尬閱讀 103評論 0 0