Android 让反射变的简单

Posted 安卓开发-顺

tags:

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

目录

一、通过反射执行方法

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

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

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

二、通过反射修改对象属性值(非final修饰)

1、获取Class对象同上,不在具体分析

2、通过Class对象获取目标属性

3、修改属性值


一、通过反射执行方法

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

第一步:获取Class对象

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

第三步:执行方法

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

package com.zs.test;

import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.zs.test.reflex.ReflexUtil;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

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

        //示例二、通过反射修改对象属性值
        //第一步 获取class对象
        Class<ReflexUtil> reflexUtilClass = ReflexUtil.class;
        //第二步 获取指定属性
        try 
            Field age = reflexUtilClass.getDeclaredField("age");
            //第三步 修改属性值
            //设置权限
            age.setAccessible(true);
            //构造对象
            ReflexUtil reflexUtil = reflexUtilClass.newInstance();
            age.set(reflexUtil,30);
            int age2 = reflexUtil.getAge();
            Log.i("ZS","=== reflex age2 == " + age2);
         catch (NoSuchFieldException | IllegalAccessException | InstantiationException e) 
            e.printStackTrace();
        
    

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

package com.zs.test.reflex;

import android.content.Intent;
import android.util.Log;

import com.zs.test.MainActivity;
import com.zs.test.SecondActivity;

import java.lang.reflect.Method;

/**
 * java 反射学习
 */
public class ReflexUtil 

    private int age = 25;

    public int getAge() 
        return age;
    

    /**
     * 反射调用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中的Log方法为例来分析

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

二、通过反射修改对象属性值(非final修饰)

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

第一步:获取Class对象

第二步:通过Class对象获取目标属性

第三步:修改属性值

1、获取Class对象同上,不在具体分析

Class<ReflexUtil> reflexUtilClass = ReflexUtil.class;

2、通过Class对象获取目标属性

Field age = reflexUtilClass.getDeclaredField("age");

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

Field getField(String name) -- 获取类本身或者父类定义的public字段

Field[] getFields() -- 获取类本身或者父类定义的所有public字段

Field getDeclaredField(String name) -- 获取类本身定义的字段(public、protected、private)

Field[] getDeclaredFields() -- 获取类本身定义的所有字段(public、protected、private)

3、修改属性值

(1)针对private方法要进行权限设置
         age .setAccessible(true);
(2)静态属性直接修改即可,对象实例传null就可以,瞎传也行,根本不校验
         age.set(null,30);
(3)非静态方法必须构造一个对象出来

         ReflexUtil reflexUtil = reflexUtilClass.newInstance();

(4)修改属性值

           age.set(reflexUtil,30);

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

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

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

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

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

怎样理解变量

一篇入门 -- Scala 反射