天天看点

反射在android中的应用

1.前言:

  • 反射:动态加载一个由我们指定的类,获取其所有的内容(成员变量、成员函数、构造函数),简而言之反射就是对一个类进行了全面的解剖。同时,反射增强了一个程序的扩展性。
  • android中目前接触使用场景:
    1. 兼容平台。android现在主流平台是基于高通、MTK,当我们开发一些系统内置app时会遇到平台的差异性,比如MTK开放的NVRAMgent在高通平台就没有,这就需要我们兼容平台合作的公司可能就给你几个接口让你去调用,这时反射技术动态加载就派上了用场。
    2. @hide隐藏的方法。Google之所以使用@hide标记主要是考虑到安全性以及此方法或者类目前还不完善后续的API可能会开放。想要调用@hide标记的方法通常我们使用反射技术来绕开权限实现调用,当然你有android源码的话可以在源码环境下import导包就可以调用;或者将@hide标记删除重新编译一份SDK。这个标记的作用更多的是方便硬件厂商做闭源的二次开发。

2.反射三步走

  • 获取class对象,即获取到指定类名称的字节码文件对象。
  • 实例化对象,为获取构造函数、成员变量、成员函数作准备。
  • 访问属性、调用函数、调用构造函数创建的对象。

2.1获取class对象

a. 指定类名后通过forName方法获取class对象,这种方式只要有名称即可,更方便,扩展性更强。执行静态块、不执行动态构造块。

Class<?> aClass=Class.forName("com.example.reflect.Test");
           

b. 通过类名.class方式获得。不执行静态块和动态构造块语句。

Class<?> aClass=Test.class;
           

c. 对象名.getClass()方法获取。需要创建对象,静态块和动态构造块均会执行。

Test test=new Test();
    Class<?> tClass=test.getClass();
           

2.2获取反射类的三个重要信息

在获取到class对象后,接着无非就是获取类的属性、方法、构造函数来为对象所用。下面介绍这三个重要信息的获取。

  • 构造函数获取

    在java中构造函数创建了对象,为对象分配了内存空间、并初始化了一些属性。反射获取构造函数能使我们动态的创建对象。

//根据指定的参数获取匹配的构造函数,仅能获取public构造函数
    Constructor getConstructor(Class[] params);
    //根据指定的参数获取匹配的构造函数,能获取所有构造函数
    Constructor getDeclaredConstructor(Class[] params);
    //不明确构造函数参数列表时获取所有的public构造函数
    Constructor[] getConstructors();
    //不明确构造函数参数列表时获取所有的构造函数
    Constructor[] getDeclaredConstructors();
           
  • 成员函数获取

    构造函数创建了对象,获取成员函数使得对象具有行为的特征,成员函数的调用执行才是绝大多数对象存在的证据和意义。成员函数获取和构造函数的获取十分相近,权限意义也可以类似理解。

//根据指定函数名称name、参数列表获取其方法仅public修饰的    
    Method getMethod(String name, Class[] params);
    //根据指定函数名称name、参数列表获取其所有方法
    Method getDeclaredMethod(String name, Class[] params);
    //不明确成员函数时获取所有public修饰的方法
    Method[] getMethods();
    //不明确成员函数时获取所有方法
    Method[] getDeclaredMethods();
           
  • 成员变量获取

    成员变量,我们经常叫做一个对象的域。从内存的角度来说,构造函数和成员函数都仅仅是Java对象的行为或过程,而成员变量则是真正构成对象本身的细胞和血肉。简单的说,就是成员变量占用的空间之和几乎就是对象占用的所有内存空间。

//根据指定的name获取public修饰的成员变量
    Field getField(String name);
    //根据指定的name可以获取private修饰的成员变量    
    Field getDeclaredField(String name);
    //获取所有的public成员变量    
    Field[] getFields();
    //获取所有的成员变量        
    Field[] getDeclaredFields();
           

2.3访问和调用需要获取的信息

我们获取的信息其实都是属于类的,而不是对象。对于类的信息提取,其实并不涉及到对象内存,在程序编译完成的那一刻起,一切都已经是确定的了。因此,它并不能算“动态”。而如何对对象内存进行操作和访问,才是“动”的真正含义。

  • 创建对象

    Constructor支持泛型,也就是它本身应该是Constructor< T >。这个类有一个public成员函数,T newInstance(Object… args),其中args为对应的参数。我们正是通过它来实现创建对象。

Object object=newInstance(args);
    //Test t=(Test)newInstance(args);
           
  • 调用成员函数

    invoke是调用执行反射的方法从属于Method 类,其第一个参数为对象,后面为反射函数传入的参数值,如果反射函数有返回类型值需要转为对应类型;如果反射函数为static修饰的,第一参数可以传入null,因为static修饰的函数属于类而不是对象,因此也不用创建对象。

Object invoke(Object receiver,  arg1,arg21,....,agrs);
           
  • 调用成员变量

    Field类有两个public方法,分别对应读与写,如下。object参数需要传入的对象,原理类似于成员方法需要指明对象一样。如果是静态属性,此值同样可以为null。

Object get(Object object)
void set(Object object, Object value)
           
  • 参考:
http://www.blogjava.net/zh-weir/archive/2011/03/26/347063.html