上一篇
安卓反射api
- 行业动态
- 2025-04-23
- 4995
安卓反射API可动态访问类成员,常用于框架内部,但存在性能损耗和安全风险
安卓反射API详解
反射基础概念
反射是指在程序运行时动态获取类信息(如类名、方法、字段等)并操作类/对象的能力,在安卓开发中,反射常用于:
- 调用隐藏API或私有方法
- 动态加载未提前引用的类
- 跨进程访问对象(如AIDL)
- 实现插件化框架
获取Class对象的三种方式
方式 | 适用场景 | 代码示例 |
---|---|---|
Class.forName("全类名") | 动态加载未知类 | Class.forName("com.example.MyClass") |
对象.getClass() | 获取对象所属类 | myObject.getClass() |
类名.class | 编译时已知类 | MyClass.class |
// 示例:通过类名字符串获取Class对象 try { Class<?> clazz = Class.forName("com.example.MyClass"); } catch (ClassNotFoundException e) { e.printStackTrace(); }
调用任意方法(含私有方法)
获取Method对象:
getMethod(String name, Class... parameterTypes)
:获取公共方法getDeclaredMethod(String name, Class... parameterTypes)
:获取所有方法(包括私有)
执行方法:
Method method = clazz.getDeclaredMethod("privateMethod", String.class); method.setAccessible(true); // 解除私有限制 Object result = method.invoke(objectInstance, "参数值");
参数类型 | 说明 |
---|---|
Object receiver | 方法所属对象实例,静态方法传null |
Object... args | 方法参数值数组 |
访问/修改字段(含私有字段)
获取Field对象:
getField(String name)
:获取公共字段getDeclaredField(String name)
:获取所有字段
操作字段:
Field field = clazz.getDeclaredField("mPrivateField"); field.setAccessible(true); Object value = field.get(objectInstance); // 获取值 field.set(objectInstance, newValue); // 修改值
创建实例(含私有构造函数)
Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, int.class); constructor.setAccessible(true); Object instance = constructor.newInstance("参数1", 123);
注意事项
安全性限制:
- Android P+ 限制反射调用隐藏API(需设置
android:exported
) - 部分系统类会抛出
IllegalAccessException
- Android P+ 限制反射调用隐藏API(需设置
性能损耗:
- 反射调用比直接调用慢约10-50倍
- 建议缓存
Method/Field/Constructor
对象
异常处理:
- 必须捕获
SecurityException
(安卓9+) - 处理
NoSuchMethodException
/IllegalAccessException
等
- 必须捕获
常见问题与解决方案
问题现象 | 解决方案 |
---|---|
Method.invoke() 返回null | 确认方法返回类型非void,且正确处理基本类型包装类 |
NoSuchMethodException | 检查方法名拼写和参数类型匹配 |
IllegalAccessException | 添加method.setAccessible(true) |
安卓9+反射失败 | 添加<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/> |
相关问题与解答
Q1:如何判断某个方法是否存在?
解答:可以通过捕获NoSuchMethodException
来判断,也可以使用Class.getMethods()
遍历:
boolean hasMethod = false; try { clazz.getMethod("methodName", String.class); hasMethod = true; } catch (NoSuchMethodException e) { hasMethod = false; }
Q2:反射调用性能如何优化?
解答:
- 缓存反射对象:
private static final Method sMethod = clazz.getDeclaredMethod(...);
- 避免重复获取Class对象,使用
Class.forName()
时开启缓存 - 尽量减少反射调用频率,批量处理时合并反射