Android 让反射变的简单

Posted 安卓开发-顺

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 让反射变的简单相关的知识,希望对你有一定的参考价值。

一、通过反射执行方法

进入主题,先列出核心步骤。

第一步:获取Class对象

第二步:通过Class对象获取要执行的方法

第三步:执行方法

下面用一个简单的例子来演示下,一个MainActivity,一个ReflexUtil类,先贴上代码

public class MainActivity extends AppCompatActivity 
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        ReflexUtil.testReflexMethod(this);


        try 
            //第一步 获取class对象
            //方式一 通过对象实例的getClass方法来获取
            ReflexUtil reflexUtil = new ReflexUtil();
            Class<? extends ReflexUtil> aClass = reflexUtil.getClass();
            //方式二 通过类名.class获取
//            Class<ReflexUtil> aClass = ReflexUtil.class;
//            Class<?> aClass = Class.forName("com.zs.test.reflex.ReflexUtil");
            //第二步 获取方法
            Method method = aClass.getDeclaredMethod("Log", String.class);
            //针对private方法进行权限设置
            method.setAccessible(true);
            //第三步 执行此方法
            //静态方法直接调用即可 传入当前方法所属对象
//            method.invoke(null, "tttttttttttt");
            //非静态方法必须构造一个对象出来 这里演示通过构造方法来构造,其实可以直接使用reflexUtil 不用构造
            //直接使用上面创建的reflexUtil实例
//            method.invoke(reflexUtil,"not static");
            Constructor<?> constructor = aClass.getConstructor();
            Object target = constructor.newInstance();
            method.invoke(target,"not static");
         catch (Exception e) 
            Log.i("ZS","=== reflex error == " + e.toString());
            e.printStackTrace();
        
    

    private void toast(String content, boolean isShow) 
        if (isShow) 
            Toast.makeText(this, content, Toast.LENGTH_LONG).show();
        
    

public class ReflexUtil 

    /**
     * 反射调用MainActivity的startActivity方法
      * @param activity
     */
    public static void testReflexMethod(MainActivity activity) 
        //第一步: 获取 class对象
        //方式1、通过类名.直接获取
        Class<MainActivity> class1 = MainActivity.class;
        //方式2、通过调用对象的getClass来获取
        Class<? extends MainActivity> class2 = activity.getClass();
        //方式3、通过Class.forName(全路径)来获取
        try 
            Class<?> class3 = Class.forName("com.zs.test.MainActivity");
         catch (ClassNotFoundException e) 
            e.printStackTrace();
        

        //第二步:获取对应方法
        try 
            //获取类本身或者父类定义的public方法 参数一是方法名 参数二是参数
            Method startActivity = class1.getMethod("startActivity", Intent.class);
            Intent intent = new Intent(activity, SecondActivity.class);
            //第三步 执行方法
            startActivity.invoke(activity, intent);

            //获取类本身定义的方法(public/protected/private)
            Method toast = class2.getDeclaredMethod("toast", String.class, boolean.class);
            //针对私有方法进行权限授予
            toast.setAccessible(true);
            //第三步 执行方法
            toast.invoke(activity, "hhh", true);
         catch (Exception e) 
            e.printStackTrace();
        
    

    /**
     * 我们假设此方法是系统隐藏方法,普通方式调用不到
     * @param s
     */
    private void Log(String s)
        Log.i("ZS"," =============== " + s);
    

代码如上图所示,下面以获取ReflectUtil对象为例来分析

1、先分析第一步获取Class对象

  • 方式1、通过调用对象实例的getClass来获取

        ReflexUtil reflexUtil = new ReflexUtil();
        Class<? extends ReflexUtil> aClass = reflexUtil.getClass();

  • 方式2、通过类名.class来获取

        Class<ReflexUtil> aClass = ReflexUtil.class;

  • 方式3、通过Class.forName(全路径)来获取

        try
            Class<?> class3 = Class.forName("com.zs.test.MainActivity");
        catch (ClassNotFoundException e)
            e.printStackTrace();
       

这三种方式有何区别?我个人推荐的使用顺序是方式一 > 方式二 >方式三

方式一 可以直接得到对象的实例,后续执行方法时也无需再通过构造函数构造对象(静态方法除外,因为静态方法不需要构建对象实例,下面还会讲到),是我个人最优推荐

方式二 很简单也很好理解,只是不能拿到对象实例,后续还要构造对象实例,是我个人次优推荐

方式三 很强大如果前两种方式都不能用就用此方式来获取,其缺点是手写路径容易出错,类全路径可能会变,类也可能会消失(比如这个类被删除了),还要构造对象实例,是我个人最后推荐

2、在分析第二步,通过Class对象获取要执行的方法

Method method = aClass.getDeclaredMethod("Log", String.class);

目标方法是这样的,贴出来
private void Log(String s)
    Log.i("ZS"," =============== " + s);

解释下这里的 getDeclaredMethod

参数1:方法名

参数2...n 该方法需要的参数的类型,比如还有第三个参数是个boolean值,就变成

Method method = aClass.getDeclaredMethod("Log", String.class,boolean.class);

获取方法还有其他方式,区别如下:

Method getMethod(String name, Class[] params) -- 获取类本身或者父类定义的public方法

Method[] getMethods() -- 获取类本身或者父类定义的所有public方法

Method getDeclaredMethod(String name, Class[] params) --获取类本身定义的方法(public/protected/private

Method[] getDeclaredMethods() -- 获取类本身定义的所有方法(public/protected/private

3、最后分析第三步,执行方法

(1)针对private方法要进行权限设置
         method.setAccessible(true);
(2)静态方法直接调用即可,对象实例传null就可以,瞎传也行,根本不校验
         method.invoke(null, "tttttttttttt");
(3)非静态方法必须构造一个对象出来

         //方式一、通过对象的newInstance()方法来构造 调用的是默认的空构造方法

         ReflexUtil reflexUtil = aClass.newInstance();

        //方式二、通过对象的构造方法来构造,这种方式可以指定构造方法

         Constructor<?> constructor = aClass.getConstructor();

         Object target = constructor.newInstance();

        //假如有个string参数的构造方法可以这么写来得到         

        Constructor<?> constructor = aClass.getConstructor(String.class);
        Object target = constructor.newInstance("aaa");
(4)执行目标方法

         method.invoke(target,"not static");

二、通过反射获取对象属性

以上是关于Android 让反射变的简单的主要内容,如果未能解决你的问题,请参考以下文章

Android 让滑动冲突变的简单(含源码分析)

Android 让滑动冲突变的简单(含源码分析)

Android 让滑动冲突变的简单(含源码分析)

Java反射机制的原理及在Android下的简单应用

充电设施接口测试的新国标及将发布——赶紧行动起来吧南京良电让充电桩生产变的简单可靠

Android EventBus框架之源码简单解析