美文网首页
java反射

java反射

作者: flynnny | 来源:发表于2021-02-21 01:15 被阅读0次

    定义

    JAVA 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为 java 语言的反射机制。

    用途

    在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用 Java 的反射机制通过反射来获取所需的私有成员或是方法。
    当然,也不是所有的都适合反射,之前就遇到一个案例,通过反射得到的结果与预期不符。阅读源码发现,经过层层调用后在最终返回结果的地方对应用的权限进行了校验,对于没有权限的应用返回值是没有意义的缺省值,否则返回实际值起到保护用户的隐私目的。

    反射机制的相关类
    与 Java 反射相关的类如下:

    1.png

    Class 类
    Class 代表类的实体,在运行的 Java 应用程序中表示类和接口。在这个类中提供了很多有用的方法,这里对他们简单的分类介绍。
    • 获得类相关的方法

    2.png

    • 获得类中属性相关的方法

    3.png

    • 获得类中注解相关的方法

    4.png

    • 获得类中构造器相关的方法

    5.png

    • 获得类中方法相关的方法

    6.png

    • 类中其他重要的方法

    7.png

    Field 类
    Field 代表类的成员变量(成员变量也称为类的属性)。

    8.png

    Method 类
    Method 代表类的方法。

    9.png

    Constructor 类
    Constructor 代表类的构造方法。

    10.png

    示例
    为了演示反射的使用,首先构造一个与书籍相关的 model——Book.java,然后通过反射方法示例创建对象、反射私有构造方法、反射私有属性、反射私有方法,最后给出两个比较复杂的反射示例——获得当前 ZenMode 和关机 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";
     // 创建对象
     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,bo
    olean.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 输出结果如下:

    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 提供的相关文档和示例。
    在阅读 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:24
    0)
    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
    

    相关文章

      网友评论

          本文标题:java反射

          本文链接:https://www.haomeiwen.com/subject/hgacfltx.html