Java高級特性——反射

概述

定義

JAVA反射機制是在運行狀態中,對於任意一個類,都可以知道這個類的全部屬性和方法;對於任意一個對象,都可以調用它的任意方法和屬性;這種動態獲取信息以及動態調用對象方法的功能稱爲java語言的反射機制。php

用途

在平常的第三方應用開發過程當中,常常會遇到某個類的某個成員變量、方法或是屬性是私有的或是隻對系統應用開放,這時候就能夠利用Java的反射機制經過反射來獲取所需的私有成員或是方法。固然,也不是全部的都適合反射,以前就遇到一個案例,經過反射獲得的結果與預期不符。閱讀源碼發現,通過層層調用後在最終返回結果的地方對應用的權限進行了校驗,對於沒有權限的應用返回值是沒有意義的缺省值,不然返回實際值起到保護用戶的隱私目的。html

反射機制的相關類

與Java反射相關的類以下:java

類名 用途
Class類 表明類的實體,在運行的Java應用程序中表示類和接口
Field類 表明類的成員變量(成員變量也稱爲類的屬性)
Method類 表明類的方法
Constructor類 表明類的構造方法

Class類

Class表明類的實體,在運行的Java應用程序中表示類和接口。在這個類中提供了不少有用的方法,這裏對他們簡單的分類介紹。android

  • 得到類相關的方法
方法 用途
asSubclass(Class<U> clazz) 把傳遞的類的對象轉換成表明其子類的對象
Cast 把對象轉換成表明類或是接口的對象
getClassLoader() 得到類的加載器
getClasses() 返回一個數組,數組中包含該類中全部公共類和接口類的對象
getDeclaredClasses() 返回一個數組,數組中包含該類中全部類和接口類的對象
forName(String className) 根據類名返回類的對象
getName() 得到類的完整路徑名字
newInstance() 建立類的實例
getPackage() 得到類的包
getSimpleName() 得到類的名字
getSuperclass() 得到當前類繼承的父類的名字
getInterfaces() 得到當前類實現的類或是接口
  • 得到類中屬性相關的方法
方法 用途
getField(String name) 得到某個公有的屬性對象
getFields() 得到全部公有的屬性對象
getDeclaredField(String name) 得到某個屬性對象
getDeclaredFields() 得到全部屬性對象
  • 得到類中註解相關的方法
方法 用途
getAnnotation(Class<A> annotationClass) 返回該類中與參數類型匹配的公有註解對象
getAnnotations() 返回該類全部的公有註解對象
getDeclaredAnnotation(Class<A> annotationClass) 返回該類中與參數類型匹配的全部註解對象
getDeclaredAnnotations() 返回該類全部的註解對象
  • 得到類中構造器相關的方法
方法 用途
getConstructor(Class...<?> parameterTypes) 得到該類中與參數類型匹配的公有構造方法
getConstructors() 得到該類的全部公有構造方法
getDeclaredConstructor(Class...<?> parameterTypes) 得到該類中與參數類型匹配的構造方法
getDeclaredConstructors() 得到該類全部構造方法
  • 得到類中方法相關的方法
方法 用途
getMethod(String name, Class...<?> parameterTypes) 得到該類某個公有的方法
getMethods() 得到該類全部公有的方法
getDeclaredMethod(String name, Class...<?> parameterTypes) 得到該類某個方法
getDeclaredMethods() 得到該類全部方法
  • 類中其餘重要的方法
方法 用途
isAnnotation() 若是是註解類型則返回true
isAnnotationPresent(Class<? extends Annotation> annotationClass) 若是是指定類型註解類型則返回true
isAnonymousClass() 若是是匿名類則返回true
isArray() 若是是一個數組類則返回true
isEnum() 若是是枚舉類則返回true
isInstance(Object obj) 若是obj是該類的實例則返回true
isInterface() 若是是接口類則返回true
isLocalClass() 若是是局部類則返回true
isMemberClass() 若是是內部類則返回true

Field類

Field表明類的成員變量(成員變量也稱爲類的屬性)。git

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

Method類

Method表明類的方法。github

方法 用途
invoke(Object obj, Object... args) 傳遞object對象及參數調用該對象對應的方法

Constructor類

Constructor表明類的構造方法。數組

方法 用途
newInstance(Object... initargs) 根據傳遞的參數建立類的對象

示例

爲了演示反射的使用,首先構造一個與書籍相關的model——Book.java,而後經過反射方法示例建立對象、反射私有構造方法、反射私有屬性、反射私有方法,最後給出兩個比較複雜的反射示例——得到當前ZenMode和關機Shutdown。bash

  • 被反射類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";

    // 建立對象
    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進階之光");
            book.setAuthor("劉望舒");
            Log.d(TAG,"reflectNewInstance book = " + book.toString());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    // 反射私有的構造方法
    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開發藝術探索","任玉剛");
            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();
        }
    }

    // 得到系統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;
    }

    // 關閉手機
    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);
            // 調用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);
            // 調用asInterface方法獲取IPowerManager對象
            Object oIPowerManager = asInterface.invoke(null, oRemoteService);
            if (shutdown) {
                // 得到shutdown()方法
                Method shutdownMethod = oIPowerManager.getClass().getMethod(
                        "shutdown", boolean.class, String.class, boolean.class);
                // 調用shutdown()方法
                shutdownMethod.invoke(oIPowerManager, confirm, null, false);
            } else {
                // 得到reboot()方法
                Method rebootMethod = oIPowerManager.getClass().getMethod("reboot",
                        boolean.class, String.class, boolean.class);
                // 調用reboot()方法
                rebootMethod.invoke(oIPowerManager, confirm, null, false);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • 調用相應反射邏輯方法
try {
            // 建立對象
            ReflectClass.reflectNewInstance();

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

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

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

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

Log輸出結果以下:app

08-27 15:11:37.999 11987-11987/com.android.peter.reflectdemo D/peter.log.ReflectClass: reflectNewInstance book = Book{name='Android進階之光', author='劉望舒'}
08-27 15:11:38.000 11987-11987/com.android.peter.reflectdemo D/peter.log.ReflectClass: reflectPrivateConstructor book = Book{name='Android開發藝術探索', 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

總結

本文列舉了反射機制使用過程當中經常使用的、重要的一些類及其方法,更多信息和用法須要近一步的閱讀Google提供的相關文檔和示例。ide

在閱讀Class類文檔時發現一個特色,以經過反射得到Method對象爲例,通常會提供四種方法,getMethod(parameterTypes)、getMethods()、getDeclaredMethod(parameterTypes)和getDeclaredMethods()。getMethod(parameterTypes)用來獲取某個公有的方法的對象,getMethods()得到該類全部公有的方法,getDeclaredMethod(parameterTypes)得到該類某個方法,getDeclaredMethods()得到該類全部方法。帶有Declared修飾的方法能夠反射到私有的方法,沒有Declared修飾的只能用來反射公有的方法。其餘的Annotation、Field、Constructor也是如此。

在ReflectClass類中還提供了兩種反射PowerManager.shutdown()的方法,在調用的時候會輸出以下log,提示沒有相關權限。以前在項目中嘗試反射其餘方法的時候還遇到過有權限和沒權限返回的值不同的狀況。若是源碼中明確進行了權限驗證,而你的應用又沒法得到這個權限的話,建議就不要浪費時間反射了。

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

參考文獻

認識反射機制(Reflection)
Java 反射機制
一個例子讓你瞭解Java反射機制
Java反射機制的原理及在Android下的簡單應用
java中的反射機制
Android註解與反射機制
java.lang.reflect.Method

做者:peter_RD_nj 連接:https://www.jianshu.com/p/9be58ee20dee 來源:簡書
相關文章
相關標籤/搜索