Java高級(jí)特性——反射

概述

定義

JAVA反射機(jī)制是在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)類,都能夠知道這個(gè)類的所有屬性和方法;對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意方法和屬性;這種動(dòng)態(tài)獲取信息以及動(dòng)態(tài)調(diào)用對(duì)象方法的功能稱為java語(yǔ)言的反射機(jī)制。

用途

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

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

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

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

Class類

Class代表類的實(shí)體,在運(yùn)行的Java應(yīng)用程序中表示類和接口。在這個(gè)類中提供了很多有用的方法,這里對(duì)他們簡(jiǎn)單的分類介紹。

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

Field類

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

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

Method類

Method代表類的方法。

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

Constructor類

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

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

示例

為了演示反射的使用,首先構(gòu)造一個(gè)與書(shū)籍相關(guān)的model——Book.java,然后通過(guò)反射方法示例創(chuàng)建對(duì)象、反射私有構(gòu)造方法、反射私有屬性、反射私有方法,最后給出兩個(gè)比較復(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)建對(duì)象
    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開(kāi)發(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對(duì)象
            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)建對(duì)象
            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開(kāi)發(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ī)制使用過(guò)程中常用的、重要的一些類及其方法,更多信息和用法需要近一步的閱讀Google提供的相關(guān)文檔和示例。

在閱讀Class類文檔時(shí)發(fā)現(xiàn)一個(gè)特點(diǎn),以通過(guò)反射獲得Method對(duì)象為例,一般會(huì)提供四種方法,getMethod(parameterTypes)、getMethods()、getDeclaredMethod(parameterTypes)和getDeclaredMethods()。getMethod(parameterTypes)用來(lái)獲取某個(gè)公有的方法的對(duì)象,getMethods()獲得該類所有公有的方法,getDeclaredMethod(parameterTypes)獲得該類某個(gè)方法,getDeclaredMethods()獲得該類所有方法。帶有Declared修飾的方法可以反射到私有的方法,沒(méi)有Declared修飾的只能用來(lái)反射公有的方法。其他的Annotation、Field、Constructor也是如此。

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

 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)識(shí)反射機(jī)制(Reflection)
Java 反射機(jī)制
一個(gè)例子讓你了解Java反射機(jī)制
Java反射機(jī)制的原理及在Android下的簡(jiǎn)單應(yīng)用
java中的反射機(jī)制
Android注解與反射機(jī)制
java.lang.reflect.Method

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、概念 在運(yùn)行狀態(tài)中,對(duì)于任何一個(gè)類,都能夠訪問(wèn)這個(gè)類的所有屬性和方法,同時(shí)任何一個(gè)對(duì)象也都能夠調(diào)用它的任意一個(gè)...
    野狗子嗷嗷嗷閱讀 1,173評(píng)論 0 1
  • 對(duì)于Java反射,平常工作中雖然經(jīng)常用到,但一直以來(lái)都沒(méi)有系統(tǒng)總結(jié)過(guò),所以趁著目前有空總結(jié)一下,加深一下理解。 如...
    西華子閱讀 1,402評(píng)論 0 10
  • 本文內(nèi)容介紹1、類加載器2、反射構(gòu)造方法3、反射成員變量4、反射成員方法5、反射配置文件運(yùn)行類中的方法 01類加載...
    乘風(fēng)破浪的姐姐閱讀 771評(píng)論 0 5
  • 自從國(guó)家施行二胎政策,網(wǎng)上便有這么一句話,我們或許是歷史上唯一的獨(dú)生子女。誠(chéng)然,一個(gè)大家庭,祖父祖母外祖父外祖...
    虞歆wym閱讀 532評(píng)論 0 0
  • 《我將以何賀你<6>》 《我將以何賀你<7>》 文/陳星然 <八、和好不如初> 慶山愣住,想推開(kāi)她,卻又舍不得。 ...
    陳星然閱讀 453評(píng)論 2 4

友情鏈接更多精彩內(nèi)容