1、在我们开发过程中可能会遇到某些类中的方法或变量无法使用,例如加了/** {@hide} */注释的,就是一些隐藏的方法。如果我们用反射就可以轻松调用了。
2、虽然如此但反射也有缺点:
* 因为是动态执行的,效率自然没有预编译时引用现有的库效率高,就像平时我们Win32开发时,可以不用h文件,直接通过GetProcAddress一样去动态获取方法的地址。当然效率要根据复杂程度而决定,一般稍微复杂的处理性能损失可能超过20%,对于一些复杂的涉及Java自动类型转换判断,执行时间可能是直接引用的上千倍,所以最终我们调试时必须考虑性能问题。
*因为反射是动态的,所以需要处理很多异常,不然Dalvik崩溃出Force Close的概率会大很多,很简单的一个反射就需要至少3个异常捕获,本身try-catch效率就不是很高,自然进一步影响运行效率,对于Android开发我们必须考虑这些问题。
*反射因为导致代码臃肿,自然稍微复杂的几个方法实用反射将会导致代码可读性和维护性降低,如果很抽象的调用Android开发强烈不推荐这种方法。
3、反射的实际应用 private void getTestData(){
try {
StorageManager storageManager =(StorageManager)getSystemService(Context.STORAGE_SERVICE);
Class<?> aClass = Class.forName("android.os.storage.StorageManager");
Method method = aClass.getMethod("getVolumes");
method.setAccessible(true);
if (method!=null){
tv_test.setText(" "+method.invoke(storageManager));
Log.e("MainActivity","method="+method.invoke(storageManager));
}
} catch (Exception e) {
e.printStackTrace();
}
}
class.forName是包名加和类名,就是你需要获取的类的的包名+类名
getMethod里面是是要获取的方法名称
最后通过invoke就可以调用了
执行后打印的数据:
07-06 22:31:03.882 24208-24208/com.example.apple.reflection E/MainActivity: method=[VolumeInfo{private}:
type=PRIVATE diskId=null partGuid=null mountFlags=0 mountUserId=-1
state=MOUNTED
fsType=null fsUuid=null fsLabel=null
path=/data internalPath=null
, VolumeInfo{emulated}:
type=EMULATED diskId=null partGuid=null mountFlags=PRIMARY|VISIBLE
mountUserId=-1 state=MOUNTED
fsType=null fsUuid=null fsLabel=null
path=/storage/emulated internalPath=/data/media
]
4、除了上面的还可以获取对象的所有属性
// 获得对象的所有属性
Field fields[] = aClass.getDeclaredFields();
for (int i=0;i<fields.length;i++){
Field field = fields[i];
String fieldName = field.getName();
String firstLetter = fieldName.substring(0, 1).toUpperCase();
// 获得和属性对应的getXXX()方法的名字
String getMethodName = "get" + firstLetter + fieldName.substring(1);
// 获得和属性对应的setXXX()方法的名字
String setMethodName = "set" + firstLetter + fieldName.substring(1);
// 获得和属性对应的getXXX()方法
// Method getMethod = aClass.getMethod(getMethodName, new Class[] {});
// 获得和属性对应的setXXX()方法
// Method setMethod = aClass.getMethod(setMethodName, new Class[] { field.getType() });
// 调用原对象的getXXX()方法
// Object value = getMethod.invoke(new Object[] {});
// System.out.println(fieldName + ":" + value);
// 调用拷贝对象的setXXX()方法
// setMethod.invoke(aClass, new Object[] { value });
Log.e("MainActivity","fieldName="+fieldName+ " firstLetter="+firstLetter+
" getMethodName="+getMethodName);
5、获取对象的类型
//获得对象的类型:
Class classType = aClass.getClass();
// getName():获得类的完整名字;
// getFields():获得类的public类型的属性;
// getDeclaredFields():获得类的所有属性;
// getMethods():获得类的public类型的方法;
// getDeclaredMethods():获得类的所有方法;
Log.e("MainActivity","classType="+classType.getName());
最后可亲自打印上面的数据来看。