Java高級特性——反射

概述

定義

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

用途

在日常的第三方應(yīng)用開發(fā)過程中,經(jīng)常會遇到某個類的某個成員變量获三、方法或是屬性是私有的或是只對系統(tǒng)應(yīng)用開放旁蔼,這時候就可以利用Java的反射機(jī)制通過反射來獲取所需的私有成員或是方法锨苏。當(dāng)然,也不是所有的都適合反射棺聊,之前就遇到一個案例伞租,通過反射得到的結(jié)果與預(yù)期不符。閱讀源碼發(fā)現(xiàn)限佩,經(jīng)過層層調(diào)用后在最終返回結(jié)果的地方對應(yīng)用的權(quán)限進(jìn)行了校驗葵诈,對于沒有權(quán)限的應(yīng)用返回值是沒有意義的缺省值,否則返回實際值起到保護(hù)用戶的隱私目的犀暑。

反射機(jī)制的相關(guān)類

與Java反射相關(guān)的類如下:

類名 用途
Class類 代表類的實體驯击,在運行的Java應(yīng)用程序中表示類和接口
Field類 代表類的成員變量(成員變量也稱為類的屬性)
Method類 代表類的方法
Constructor類 代表類的構(gòu)造方法

Class類

Class代表類的實體,在運行的Java應(yīng)用程序中表示類和接口耐亏。在這個類中提供了很多有用的方法徊都,這里對他們簡單的分類介紹。

  • 獲得類相關(guān)的方法
方法 用途
asSubclass(Class<U> clazz) 把傳遞的類的對象轉(zhuǎn)換成代表其子類的對象
Cast 把對象轉(zhuǎn)換成代表類或是接口的對象
getClassLoader() 獲得類的加載器
getClasses() 返回一個數(shù)組广辰,數(shù)組中包含該類中所有公共類和接口類的對象
getDeclaredClasses() 返回一個數(shù)組暇矫,數(shù)組中包含該類中所有類和接口類的對象
forName(String className) 根據(jù)類名返回類的對象
getName() 獲得類的完整路徑名字
newInstance() 創(chuàng)建類的實例
getPackage() 獲得類的包
getSimpleName() 獲得類的名字
getSuperclass() 獲得當(dāng)前類繼承的父類的名字
getInterfaces() 獲得當(dāng)前類實現(xiàn)的類或是接口
  • 獲得類中屬性相關(guān)的方法
方法 用途
getField(String name) 獲得某個公有的屬性對象
getFields() 獲得所有公有的屬性對象
getDeclaredField(String name) 獲得某個屬性對象
getDeclaredFields() 獲得所有屬性對象
  • 獲得類中注解相關(guān)的方法
方法 用途
getAnnotation(Class<A> annotationClass) 返回該類中與參數(shù)類型匹配的公有注解對象
getAnnotations() 返回該類所有的公有注解對象
getDeclaredAnnotation(Class<A> annotationClass) 返回該類中與參數(shù)類型匹配的所有注解對象
getDeclaredAnnotations() 返回該類所有的注解對象
  • 獲得類中構(gòu)造器相關(guān)的方法
方法 用途
getConstructor(Class...<?> parameterTypes) 獲得該類中與參數(shù)類型匹配的公有構(gòu)造方法
getConstructors() 獲得該類的所有公有構(gòu)造方法
getDeclaredConstructor(Class...<?> parameterTypes) 獲得該類中與參數(shù)類型匹配的構(gòu)造方法
getDeclaredConstructors() 獲得該類所有構(gòu)造方法
  • 獲得類中方法相關(guān)的方法
方法 用途
getMethod(String name, Class...<?> parameterTypes) 獲得該類某個公有的方法
getMethods() 獲得該類所有公有的方法
getDeclaredMethod(String name, Class...<?> parameterTypes) 獲得該類某個方法
getDeclaredMethods() 獲得該類所有方法
  • 類中其他重要的方法
方法 用途
isAnnotation() 如果是注解類型則返回true
isAnnotationPresent(Class<? extends Annotation> annotationClass) 如果是指定類型注解類型則返回true
isAnonymousClass() 如果是匿名類則返回true
isArray() 如果是一個數(shù)組類則返回true
isEnum() 如果是枚舉類則返回true
isInstance(Object obj) 如果obj是該類的實例則返回true
isInterface() 如果是接口類則返回true
isLocalClass() 如果是局部類則返回true
isMemberClass() 如果是內(nèi)部類則返回true

Field類

Field代表類的成員變量(成員變量也稱為類的屬性)。

方法 用途
equals(Object obj) 屬性與obj相等則返回true
get(Object obj) 獲得obj中對應(yīng)的屬性值
set(Object obj, Object value) 設(shè)置obj中對應(yīng)屬性值

Method類

Method代表類的方法择吊。

方法 用途
invoke(Object obj, Object... args) 傳遞object對象及參數(shù)調(diào)用該對象對應(yīng)的方法

Constructor類

Constructor代表類的構(gòu)造方法李根。

方法 用途
newInstance(Object... initargs) 根據(jù)傳遞的參數(shù)創(chuàng)建類的對象

示例

為了演示反射的使用,首先構(gòu)造一個與書籍相關(guān)的model——Book.java几睛,然后通過反射方法示例創(chuàng)建對象房轿、反射私有構(gòu)造方法、反射私有屬性所森、反射私有方法囱持,最后給出兩個比較復(fù)雜的反射示例——獲得當(dāng)前ZenMode和關(guān)機(jī)Shutdown。

  • 被反射類Book.java
public class Book{
    private final static String TAG = "BookTag";

    private String name;
    private String author;

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

    public Book() {
    }

    private Book(String name, String author) {
        this.name = name;
        this.author = author;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    private String declaredMethod(int index) {
        String string = null;
        switch (index) {
            case 0:
                string = "I am declaredMethod 1 !";
                break;
            case 1:
                string = "I am declaredMethod 2 !";
                break;
            default:
                string = "I am declaredMethod 1 !";
        }

        return string;
    }
}
  • 反射邏輯封裝在ReflectClass.java
public class ReflectClass {
    private final static String TAG = "peter.log.ReflectClass";

    // 創(chuàng)建對象
    public static void reflectNewInstance() {
        try {
            Class<?> classBook = Class.forName("com.android.peter.reflectdemo.Book");
            Object objectBook = classBook.newInstance();
            Book book = (Book) objectBook;
            book.setName("Android進(jìn)階之光");
            book.setAuthor("劉望舒");
            Log.d(TAG,"reflectNewInstance book = " + book.toString());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    // 反射私有的構(gòu)造方法
    public static void reflectPrivateConstructor() {
        try {
            Class<?> classBook = Class.forName("com.android.peter.reflectdemo.Book");
            Constructor<?> declaredConstructorBook = classBook.getDeclaredConstructor(String.class,String.class);
            declaredConstructorBook.setAccessible(true);
            Object objectBook = declaredConstructorBook.newInstance("Android開發(fā)藝術(shù)探索","任玉剛");
            Book book = (Book) objectBook;
            Log.d(TAG,"reflectPrivateConstructor book = " + book.toString());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    // 反射私有屬性
    public static void reflectPrivateField() {
        try {
            Class<?> classBook = Class.forName("com.android.peter.reflectdemo.Book");
            Object objectBook = classBook.newInstance();
            Field fieldTag = classBook.getDeclaredField("TAG");
            fieldTag.setAccessible(true);
            String tag = (String) fieldTag.get(objectBook);
            Log.d(TAG,"reflectPrivateField tag = " + tag);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    // 反射私有方法
    public static void reflectPrivateMethod() {
        try {
            Class<?> classBook = Class.forName("com.android.peter.reflectdemo.Book");
            Method methodBook = classBook.getDeclaredMethod("declaredMethod",int.class);
            methodBook.setAccessible(true);
            Object objectBook = classBook.newInstance();
            String string = (String) methodBook.invoke(objectBook,0);

            Log.d(TAG,"reflectPrivateMethod string = " + string);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    // 獲得系統(tǒng)Zenmode值
    public static int getZenMode() {
        int zenMode = -1;
        try {
            Class<?> cServiceManager = Class.forName("android.os.ServiceManager");
            Method mGetService = cServiceManager.getMethod("getService", String.class);
            Object oNotificationManagerService = mGetService.invoke(null, Context.NOTIFICATION_SERVICE);
            Class<?> cINotificationManagerStub = Class.forName("android.app.INotificationManager$Stub");
            Method mAsInterface = cINotificationManagerStub.getMethod("asInterface",IBinder.class);
            Object oINotificationManager = mAsInterface.invoke(null,oNotificationManagerService);
            Method mGetZenMode = cINotificationManagerStub.getMethod("getZenMode");
            zenMode = (int) mGetZenMode.invoke(oINotificationManager);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return zenMode;
    }

    // 關(guān)閉手機(jī)
    public static void shutDown() {
        try {
            Class<?> cServiceManager = Class.forName("android.os.ServiceManager");
            Method mGetService = cServiceManager.getMethod("getService",String.class);
            Object oPowerManagerService = mGetService.invoke(null,Context.POWER_SERVICE);
            Class<?> cIPowerManagerStub = Class.forName("android.os.IPowerManager$Stub");
            Method mShutdown = cIPowerManagerStub.getMethod("shutdown",boolean.class,String.class,boolean.class);
            Method mAsInterface = cIPowerManagerStub.getMethod("asInterface",IBinder.class);
            Object oIPowerManager = mAsInterface.invoke(null,oPowerManagerService);
            mShutdown.invoke(oIPowerManager,true,null,true);

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public static void shutdownOrReboot(final boolean shutdown, final boolean confirm) {
        try {
            Class<?> ServiceManager = Class.forName("android.os.ServiceManager");
            // 獲得ServiceManager的getService方法
            Method getService = ServiceManager.getMethod("getService", java.lang.String.class);
            // 調(diào)用getService獲取RemoteService
            Object oRemoteService = getService.invoke(null, Context.POWER_SERVICE);
            // 獲得IPowerManager.Stub類
            Class<?> cStub = Class.forName("android.os.IPowerManager$Stub");
            // 獲得asInterface方法
            Method asInterface = cStub.getMethod("asInterface", android.os.IBinder.class);
            // 調(diào)用asInterface方法獲取IPowerManager對象
            Object oIPowerManager = asInterface.invoke(null, oRemoteService);
            if (shutdown) {
                // 獲得shutdown()方法
                Method shutdownMethod = oIPowerManager.getClass().getMethod(
                        "shutdown", boolean.class, String.class, boolean.class);
                // 調(diào)用shutdown()方法
                shutdownMethod.invoke(oIPowerManager, confirm, null, false);
            } else {
                // 獲得reboot()方法
                Method rebootMethod = oIPowerManager.getClass().getMethod("reboot",
                        boolean.class, String.class, boolean.class);
                // 調(diào)用reboot()方法
                rebootMethod.invoke(oIPowerManager, confirm, null, false);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • 調(diào)用相應(yīng)反射邏輯方法
        try {
            // 創(chuàng)建對象
            ReflectClass.reflectNewInstance();

            // 反射私有的構(gòu)造方法
            ReflectClass.reflectPrivateConstructor();

            // 反射私有屬性
            ReflectClass.reflectPrivateField();

            // 反射私有方法
            ReflectClass.reflectPrivateMethod();
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        Log.d(TAG," zenmode = " + ReflectClass.getZenMode());

Log輸出結(jié)果如下:

08-27 15:11:37.999 11987-11987/com.android.peter.reflectdemo D/peter.log.ReflectClass: reflectNewInstance book = Book{name='Android進(jìn)階之光', author='劉望舒'}
08-27 15:11:38.000 11987-11987/com.android.peter.reflectdemo D/peter.log.ReflectClass: reflectPrivateConstructor book = Book{name='Android開發(fā)藝術(shù)探索', author='任玉剛'}
08-27 15:11:38.000 11987-11987/com.android.peter.reflectdemo D/peter.log.ReflectClass: reflectPrivateField tag = BookTag
08-27 15:11:38.000 11987-11987/com.android.peter.reflectdemo D/peter.log.ReflectClass: reflectPrivateMethod string = I am declaredMethod 1 !
08-27 15:11:38.004 11987-11987/com.android.peter.reflectdemo D/peter.log.ReflectDemo:  zenmode = 0

總結(jié)

本文列舉了反射機(jī)制使用過程中常用的焕济、重要的一些類及其方法纷妆,更多信息和用法需要近一步的閱讀Google提供的相關(guān)文檔和示例。

在閱讀Class類文檔時發(fā)現(xiàn)一個特點晴弃,以通過反射獲得Method對象為例掩幢,一般會提供四種方法,getMethod(parameterTypes)上鞠、getMethods()际邻、getDeclaredMethod(parameterTypes)和getDeclaredMethods()。getMethod(parameterTypes)用來獲取某個公有的方法的對象旗国,getMethods()獲得該類所有公有的方法枯怖,getDeclaredMethod(parameterTypes)獲得該類某個方法,getDeclaredMethods()獲得該類所有方法能曾。帶有Declared修飾的方法可以反射到私有的方法度硝,沒有Declared修飾的只能用來反射公有的方法。其他的Annotation寿冕、Field蕊程、Constructor也是如此。

在ReflectClass類中還提供了兩種反射PowerManager.shutdown()的方法驼唱,在調(diào)用的時候會輸出如下log藻茂,提示沒有相關(guān)權(quán)限。之前在項目中嘗試反射其他方法的時候還遇到過有權(quán)限和沒權(quán)限返回的值不一樣的情況玫恳。如果源碼中明確進(jìn)行了權(quán)限驗證辨赐,而你的應(yīng)用又無法獲得這個權(quán)限的話,建議就不要浪費時間反射了京办。

 W/System.err: java.lang.reflect.InvocationTargetException
 W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
 W/System.err:     at .ReflectClass.shutDown(ReflectClass.java:104)
 W/System.err:     at .MainActivity$1.onClick(MainActivity.java:25)
 W/System.err:     at android.view.View.performClick(View.java:6259)
 W/System.err:     at android.view.View$PerformClick.run(View.java:24732)
 W/System.err:     at android.os.Handler.handleCallback(Handler.java:789)
 W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:98)
 W/System.err:     at android.os.Looper.loop(Looper.java:164)
 W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:6592)
 W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
 W/System.err:     at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
 W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:769)
 W/System.err: Caused by: java.lang.SecurityException: Neither user 10224 nor current process has android.permission.REBOOT.
 W/System.err:     at android.os.Parcel.readException(Parcel.java:1942)
 W/System.err:     at android.os.Parcel.readException(Parcel.java:1888)
 W/System.err:     at android.os.IPowerManager$Stub$Proxy.shutdown(IPowerManager.java:787)
 W/System.err:  ... 12 more

ReflectDemo

參考文獻(xiàn)

認(rèn)識反射機(jī)制(Reflection)
Java 反射機(jī)制
一個例子讓你了解Java反射機(jī)制
Java反射機(jī)制的原理及在Android下的簡單應(yīng)用
java中的反射機(jī)制
Android注解與反射機(jī)制
java.lang.reflect.Method

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末掀序,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子惭婿,更是在濱河造成了極大的恐慌不恭,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件财饥,死亡現(xiàn)場離奇詭異换吧,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)钥星,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門沾瓦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人谦炒,你說我怎么就攤上這事贯莺。” “怎么了编饺?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵乖篷,是天一觀的道長。 經(jīng)常有香客問我透且,道長撕蔼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任秽誊,我火速辦了婚禮鲸沮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘锅论。我一直安慰自己讼溺,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布最易。 她就那樣靜靜地躺著怒坯,像睡著了一般炫狱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上剔猿,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天视译,我揣著相機(jī)與錄音,去河邊找鬼归敬。 笑死酷含,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的汪茧。 我是一名探鬼主播椅亚,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼舱污!你這毒婦竟也來了呀舔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤慌闭,失蹤者是張志新(化名)和其女友劉穎别威,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體驴剔,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡省古,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了丧失。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片豺妓。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖布讹,靈堂內(nèi)的尸體忽然破棺而出琳拭,到底是詐尸還是另有隱情,我是刑警寧澤描验,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布白嘁,位于F島的核電站,受9級特大地震影響膘流,放射性物質(zhì)發(fā)生泄漏絮缅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一呼股、第九天 我趴在偏房一處隱蔽的房頂上張望耕魄。 院中可真熱鬧,春花似錦彭谁、人聲如沸吸奴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽则奥。三九已至考润,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背罗售。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人故河。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像诡延,于是被迫代替她去往敵國和親竭钝。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

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

  • 一燥滑、概念 在運行狀態(tài)中渐北,對于任何一個類,都能夠訪問這個類的所有屬性和方法铭拧,同時任何一個對象也都能夠調(diào)用它的任意一個...
    野狗子嗷嗷嗷閱讀 1,098評論 0 1
  • 對于Java反射赃蛛,平常工作中雖然經(jīng)常用到,但一直以來都沒有系統(tǒng)總結(jié)過搀菩,所以趁著目前有空總結(jié)一下呕臂,加深一下理解。 如...
    西華子閱讀 1,340評論 0 10
  • 本文內(nèi)容介紹1肪跋、類加載器2歧蒋、反射構(gòu)造方法3、反射成員變量4州既、反射成員方法5谜洽、反射配置文件運行類中的方法 01類加載...
    乘風(fēng)破浪的姐姐閱讀 683評論 0 5
  • 自從國家施行二胎政策,網(wǎng)上便有這么一句話吴叶,我們或許是歷史上唯一的獨生子女阐虚。誠然,一個大家庭蚌卤,祖父祖母外祖父外祖...
    虞歆wym閱讀 483評論 0 0
  • 《我將以何賀你<6>》 《我將以何賀你<7>》 文/陳星然 <八实束、和好不如初> 慶山愣住,想推開她造寝,卻又舍不得磕洪。 ...
    陳星然閱讀 395評論 2 4