详解Java编程中的反射在Android开发中的应用
反射定义
“反射”(Reflection)能够让运行于JVM中的程序检测和修改运行时的行为。
为何需要反射
反射带来的好处包括:
- 在运行时检测对象的类型。
- 动态构造某个类的对象。
- 检测类的属性和方法。
- 任意调用对象的方法。
- 修改构造函数、方法、属性的可见性。
反射方法Method
getDeclaredMethod方法
声明如下:
publicMethodgetDeclaredMethod(Stringname,Class<?>...parameterTypes)throwsNoSuchMethodException,SecurityException
解释:
返回一个Method对象,该对象反映此Class对象所表示的类或接口的指定已声明方法。
1.name:是一个String,它指定所需方法的简称。
2.parameterTypes:是一个Class对象的变长数组,它按声明顺序标识该方法的形参类型。
注意:
getDeclaredMethod获取该类声明的public方法或者protected方法,但是不包括继承的方法。
getMethod方法
声明如下:
publicMethodgetMethod(Stringname,Class<?>...parameterTypes)throwsNoSuchMethodException,SecurityException
解释:
返回一个Method对象,该对象反映此Class对象所表示的类或接口的指定公共成员方法。
1.name:是一个String,它指定所需方法的简称。
2.parameterTypes:是一个Class对象的变长数组,它按声明顺序标识该方法的形参类型。
参数解释
name参数就不需要解释了,就是调用类的方法名称。
可能很多同学刚接触这个方法的时候,会对parameterTypes参数产生疑问,例如这个参数为什么是Class泛型变长数组,其实举个例子就很好理解了。
假设我们要反射的方法有4个参数,函数原型如下:
publicvoidprintInfo(Stringstr,intiNum,doubledNum,longi);
那我们通过返回获取这个Method对象的时候,传的parameterTypes如下所示:
getMethod("printInfo",String.class,int.class,double.class,long.class);
所以,parameterTypes其实就是对方法形参的类型抽象。
invoke方法
声明如下:
publicObjectinvoke(Objectobj,Object...args)throwsIllegalAccessException,IllegalArgumentException,InvocationTargetException
解释:
Method类的invoke(Objectobj,Object…args)方法接收的参数必须为对象。其中:
1.obj:从中调用底层方法的对象。
2.args:用于方法调用的参数。
Android反射应用
我们知道,Android有些类是没有在SDK中开放的,例如你需要获取系统属性,需要调用到SystemProperties类的get方法,但是这个类并没有在SDK中公开,我们可以在Android源码中查看一下这个类:
packageandroid.os; importjava.util.ArrayList; importandroid.util.Log; /** *Givesaccesstothesystempropertiesstore.Thesystemproperties *storecontainsalistofstringkey-valuepairs. * *{@hide} */ publicclassSystemProperties { //省略具体实现代码 /** *Getthevalueforthegivenkey. *@returnanemptystringifthekeyisn'tfound *@throwsIllegalArgumentExceptionifthekeyexceeds32characters */ publicstaticStringget(Stringkey){ if(key.length()>PROP_NAME_MAX){ thrownewIllegalArgumentException("key.length>"+PROP_NAME_MAX); } returnnative_get(key); } }
可以看到,这个前面有一个@hide标签,所以这个类是没法直接在代码中调用的。
但是,在Android应用中,很多时候我们需要获取到手机类型属性(ro.product.model)。所以,这个时候,我们就需要在应用层反射SystemProperties类,调用get方法。具体实现源码如下:
importjava.lang.reflect.InvocationTargetException; importjava.lang.reflect.Method; importandroid.util.Log; publicclassSystemProperties{ publicstaticStringget(Stringkey){ Stringvalue=""; Class<?>cls=null; try{ cls=Class.forName("android.os.SystemProperties"); MethodhideMethod=cls.getMethod("get",String.class); Objectobject=cls.newInstance(); value=(String)hideMethod.invoke(object,key); }catch(ClassNotFoundExceptione){ Log.e("zhengyi.wzy","geterror()",e); }catch(NoSuchMethodExceptione){ Log.e("zhengyi.wzy","geterror()",e); }catch(InstantiationExceptione){ Log.e("zhengyi.wzy","geterror()",e); }catch(IllegalAccessExceptione){ Log.e("zhengyi.wzy","geterror()",e); }catch(IllegalArgumentExceptione){ Log.e("zhengyi.wzy","geterror()",e); }catch(InvocationTargetExceptione){ Log.e("zhengyi.wzy","geterror()",e); } returnvalue; } }