当前位置:首页 > 行业动态 > 正文

安卓反射api

安卓反射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();
}

调用任意方法(含私有方法)

  1. 获取Method对象

    • getMethod(String name, Class... parameterTypes):获取公共方法
    • getDeclaredMethod(String name, Class... parameterTypes):获取所有方法(包括私有)
  2. 执行方法

    安卓反射api  第1张

    Method method = clazz.getDeclaredMethod("privateMethod", String.class);
    method.setAccessible(true); // 解除私有限制
    Object result = method.invoke(objectInstance, "参数值");
参数类型 说明
Object receiver 方法所属对象实例,静态方法传null
Object... args 方法参数值数组

访问/修改字段(含私有字段)

  1. 获取Field对象

    • getField(String name):获取公共字段
    • getDeclaredField(String name):获取所有字段
  2. 操作字段

    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);

注意事项

  1. 安全性限制

    • Android P+ 限制反射调用隐藏API(需设置android:exported
    • 部分系统类会抛出IllegalAccessException
  2. 性能损耗

    • 反射调用比直接调用慢约10-50倍
    • 建议缓存Method/Field/Constructor对象
  3. 异常处理

    • 必须捕获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:反射调用性能如何优化?

解答

  1. 缓存反射对象:
    private static final Method sMethod = clazz.getDeclaredMethod(...);
  2. 避免重复获取Class对象,使用Class.forName()时开启缓存
  3. 尽量减少反射调用频率,批量处理时合并反射
0