java 反射

其實原本這篇文章沒啥必要,但是最近在 code review 的時候,發(fā)現(xiàn)這篇文章中下面這段代碼有些疑問,所以就去查了查

      @SuppressLint("NewApi")
    public static boolean isNotificationEnabled(Context context) {
        AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
        ApplicationInfo applicationInfo = context.getApplicationInfo();
        String pkg = context.getApplicationContext().getPackageName();
        int uid = applicationInfo.uid;
        Class appOpsClass;
        try {
            appOpsClass = Class.forName(AppOpsManager.class.getName());
            Method checkOpNoThrowMethod = appOpsClass.getMethod("checkOpNoThrow", Integer.TYPE, Integer.TYPE, String.class);
            Field opPostNotificationValue = appOpsClass.getDeclaredField("OP_POST_NOTIFICATION");
            int value = (Integer) opPostNotificationValue.get(Integer.class);
            return ((Integer) checkOpNoThrowMethod.invoke(appOpsManager, value, uid, pkg) == AppOpsManager.MODE_ALLOWED);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return false;
    }

很明顯,這段代碼中運用了反射,可是在AppOpsManager 類中的 checkOpNoThrow 方法代碼是這樣的

    /**
     * Like {@link #checkOp} but instead of throwing a {@link SecurityException} it
     * returns {@link #MODE_ERRORED}.
     * @hide
     */
    public int checkOpNoThrow(int op, int uid, String packageName) {
        try {
            return mService.checkOperation(op, uid, packageName);
        } catch (RemoteException e) {
        }
        return MODE_ERRORED;
    }

方法明明是 public ,自己還愚蠢的寫了這么一段代碼,看看能不能代替反射的那段代碼:

appOpsManager.checkOpNoThrow("OP_POST_NOTIFICATION",uid,pkg)== AppOpsManager.MODE_ALLOWED)

運行,直接crash,報錯如下:

java.lang.IllegalArgumentException: Unknown operation string: OP_POST_NOTIFICATION

仔細看了一下,AppOpsManager 類中的 checkOpNoThrow 方法,帶有 hide 標簽,去一探究竟~

「@hide」標簽

類或 API 是否開放,是通過 doc 注釋的「@hide」標簽來控制的。「@hide」標簽表示不對外公開 api,但是系統(tǒng)內部是可以使用該注釋標記的接口的。
「@hide」標簽注釋后的類或者 API 在編譯時不對外開放,但是在運行的時候這些類和 API 都是可以訪問的。
解決方案:一種是使用反射的方法得到隱藏的 API;一種是使用源碼編譯時生成的全編譯的 jar 包。

java 反射的總結

java 反射機制是在運行狀態(tài)中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意一個方法;這種動態(tài)獲取以及動態(tài)調用對象的方法的功能稱為 Java 的反射機制。

缺點:性能是一個問題,反射相當于一系列解釋操作,通知 jvm 要做的事情,性能比直接的 java 代碼要慢很多。

關于反射的參考鏈接:

http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html
http://www.cnblogs.com/whoislcj/p/6038511.html
https://segmentfault.com/a/1190000010162647

關于 hide 標簽參考的鏈接:

https://stackoverflow.com/questions/17035271/what-does-hide-mean-in-the-android-source-code
http://blog.csdn.net/ouyang_peng/article/details/17288253
http://blog.sina.com.cn/s/blog_5da93c8f0101e1yj.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容