JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

然而在android中Google很多的类的某些方法不让第三方应用去调用,通过java反射机制能把这些隐藏方法获取出来并调用,三方应用上我们就很方便的去用这些方法。

我们以android中获取StorageManager类中的getVolumePaths()方法为例:

            StorageManager sm = (StorageManager) getSystemService(STORAGE_SERVICE);            Class c=StorageManager.class;            Method method=c.getMethod("getVolumePaths",null);            String[] paths= (String[]) method.invoke(sm, null);

一、Class类

首先向大家说明一点,Class本身就是一个类,Class是该类的名称。看下面这个类的定义:
  public class MyButton extends Button {…}
  注意到上面的class的首字母是小写,它表示的是一种类类型,但是我们的Class是一个类,相当于上面定义的MyButton类。所以,千万不要把这里的Class做为一个类类型来理解。

Class类是整个Java反射机制的源头,获取Class对象的方法有三种:

  1. Class.forName(“Employee”)
  2. Employee.class
  3. Employee e = new Employee(); e.getClass();

在平时的使用,要注意对这几种方法的灵活运用,尤其是对Class.forName()方法的使用。因为在很多开发中,会直接通过类的名称取得Class类的对象。
例子中使用的是 . Class:Class c=StorageManager.class;

二、获取类的相关信息

1.获取构造方法

Class类提供了四个public方法,用于获取某个类的构造方法。

1.Constructor getConstructor(Class[] params) 根据构造函数的参2.数,返回一个具体的具有public属性的构造函数

2.Constructor getConstructors() 返回所有具有public属性的构造函数数组

3.Constructor getDeclaredConstructor(Class[] params) 根据构造函数的参数,返回一个具体的构造函数(不分public和非public属性)

4.Constructor getDeclaredConstructors() 返回该类中所有的构造函数数组(不分public和非public属性)

例如: 获取指定类的公有构造方法
Constructor[] theConstructors = c.getDeclaredConstructors();

2.获取类的成员方法

与获取构造方法的方式相同,存在四种获取成员方法的方式。

1.Method getMethod(String name, Class[] params) 根据方法名和参数,返回一个具体的具有public属性的方法

2.Method[] getMethods() 返回所有具有public属性的方法数组

3.Method getDeclaredMethod(String name, Class[] params) 根据方法名和参数,返回一个具体的方法(不分public和非public属性)

4.Method[] getDeclaredMethods() 返回该类中的所有的方法数组(不分public和非public属性)

注意:方法getDeclaredMethods()只能获取到由当前类定义的所有方法,不能获取从父类继承的方法;方法getMethods() 不仅能获取到当前类定义的public方法,也能得到从父类继承和已经实现接口的public方法。

3.获取类的成员变量

存在四种获取成员属性的方法:

1.Field getField(String name) 根据变量名,返回一个具体的具有public属性的成员变量

2.Field[] getFields() 返回具有public属性的成员变量的数组

3.Field getDeclaredField(String name) 根据变量名,返回一个成员变量(不分public和非public属性)

4.Field[] getDelcaredField() 返回所有成员变量组成的数组(不分public和非public属性)

4.Method

Method类中包含着类的成员方法的信息。在Method类中有一个public成员函数:Object invoke(Object receiver, Object… args),参数receiver指明了调用对象,参数args指明了该方法所需要接收的参数。由于我们是在运行时动态的调用类的方法,无法提前知道该类的参数类型和返回值类型,所以传入的参数的类型是Object,返回的类型也是Object。(因为Object类是所有其他类的父类)
  如果某一个方法是Java类的静态方法,那么Object receiver参数可以传入null,因为静态方法从不属于对象。

Method中的receiver代表要调用方法所在类的实例,要调用一个类的方法,首先需要一个该类的实例(当然,如果该类是static,就不需要实例了,至于原因,你懂得!)。

在得到一个类的Class对象之后,我们可以利用类Constructor去实例化该对象。Constructor支持泛型,也就是它本身应该是Constructor。这个类有一个public成员函数:T newInstance(Object… args),其中args为对应的参数,我们通过Constructor的这个方法来创建类的对象实例。
  在代码LoadMethod.java和LoadMethodEx.java中,分别给出了两种实例化Class类的方法:一种是利用Constructor类调用newInstance()方法;另一种就是利用Class类本身的newInstance()方法创建一个实例。两种方法实现的效果是一样的。
// 利用newInstance()方法,获取构造方法的实例

// Class的newInstance方法,仅提供默认无参的实例化方法,类似于无参的构造方法

// Constructor的newInstance方法,提供了带参数的实例化方法,类似于含参的构造方法

Constructor ct = cls.getConstructor(null);

Object obj = ct.newInstance(null);

Object obj = cls.newInstance();

例子中的String[] paths= (String[]) method.invoke(sm, null);
sm就是StorageManager类的实例,我们通过StorageManager sm = (StorageManager) getSystemService(STORAGE_SERVICE);得到的。由于getVolumePaths()方法中没有参数,传入null就可以了;

使用

上面说的基本都是获取方式,下面透过一个例子来实际使用他们:
首先创建一个用于反射的类并创建一些成员变量、方法等属性:

public class ReflectTest {    public String testPublicFiled;    private String testPrivateFiled;    public ReflectTest() {    }    public ReflectTest(String testPublicFiled, String testPrivateFiled) {        this.testPublicFiled = testPublicFiled;        this.testPrivateFiled = testPrivateFiled;    }    public void testPublicMethod(String name) {    }    private String testPrivateMethod() {        return null;    }}

然后在其他地方通过反射获取这个类的信息:

 public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {        //获取类        Class c = Class.forName("com.shenhesoft.lib.ReflectTest");        //获取继承的父类        String superClass = c.getSuperclass().getSimpleName();        System.out.println(superClass);        System.out.println("------------------------------");        //获取实现的接口        Class[] interfaces = c.getInterfaces();        for (int i = 0; i < interfaces.length; i++) {            System.out.println(interfaces[i].getSimpleName());        }        System.out.println("-----------------------------");        //获取类中所有的成员变量        Field[] fields = c.getDeclaredFields();        for (int i = 0; i < fields.length; i++) {            //参数修饰类型            String modifyName = Modifier.toString(fields[i].getModifiers());            //参数类型            String argsTypeName = fields[i].getType().getSimpleName();            //参数名            String argsName = fields[i].getName();            System.out.println(modifyName + " " + argsTypeName + " " + argsName);        }        //获取指定名称的变量        Field field = c.getDeclaredField("testPublicFiled");        //省略。。。。。。。。。        System.out.println("-------------------------------");        //获取类中所有的方法        Method[] methods = c.getDeclaredMethods();        for (int i = 0; i < methods.length; i++) {            //方法修饰类型            String modifyName = Modifier.toString(methods[i].getModifiers());            //方法返回类型            String returnType = methods[i].getReturnType().getSimpleName();            //方法名            String methodName = methods[i].getName();            //方法里的参数类型            Class[] parameterTypes = methods[i].getParameterTypes();            String paramType = "";            for (int i1 = 0; i1 < parameterTypes.length; i1++) {                paramType = paramType + parameterTypes[i1].getSimpleName() + " ";            }            System.out.println(modifyName + " " + returnType + " " + methodName + " " + paramType);        }        //获取指定名称的方法        Method method = c.getDeclaredMethod("testPublicMethod", String.class);        //省略。。。。。。。。。        System.out.println("---------------------------------");        //获取类中所有的构造方法        Constructor[] constructors = c.getDeclaredConstructors();        for (int i = 0; i < constructors.length; i++) {            //获取构造方法的修饰类型            String modifyName = Modifier.toString(constructors[i].getModifiers());            //获取构造函数的参数类型            Class[] parameterTypes = constructors[i].getParameterTypes();            String paramType = "";            for (int i1 = 0; i1 < parameterTypes.length; i1++) {                paramType = paramType + parameterTypes[i1].getSimpleName() + " ";            }            System.out.println(modifyName + " " + paramType);        }        //获取指定名称的方法        Constructor constructor = c.getDeclaredConstructor(null);        //省略。。。。。。。。。    }

前面写的那么多方法在这里就用到了,我就不一一的讲了,对照着注释和前面的文字就能看懂,其实调用的方法就那么几个。

通过反射操作对象

想要操作对象首先要获取到这个对象,然后才能通过反射操作这个对象,有些人可能会问,我已经有这个对象了可以直接操作为什么还要通过反射操作,这个问题的答案就是反射的核心。你有了对象可以直接操作私有的成员变量和方法吗,可以修改final修饰的成员变量吗,显然是不行的,下面我们看一下反射怎么做到这些。
修改ReflectTest类如下:

public class ReflectTest {    public String testPublicFiled;    private String testPrivateFiled;    public ReflectTest() {    }    public ReflectTest(String testPublicFiled, String testPrivateFiled) {        this.testPublicFiled = testPublicFiled;        this.testPrivateFiled = testPrivateFiled;    }    public void testPublicMethod(String name) {        System.out.println("公共方法,参数:" + name);    }    private void testPrivateMethod() {        System.out.println("私有方法");    }    public String getTestPublicFiled() {        return testPublicFiled;    }    public String getTestPrivateFiled() {        return testPrivateFiled;    }}

下面我们直接通过反射修改ReflectTest的私有成员变量testPrivateFiled:

    public static void main(String[] args) throws Exception{        //获取类        Class c = Class.forName("com.shenhesoft.lib.ReflectTest");        //创建一个对象        ReflectTest reflectTest = new ReflectTest("公共参数默认值", "私有参数默认值");        //打印私有参数的值        System.out.println(reflectTest.getTestPrivateFiled());        //获取私有的成员变量        Field field = c.getDeclaredField("testPrivateFiled");        //设置可以访问私有的成员变量,重要        field.setAccessible(true);        //获取私有成员变量的值        String s = (String) field.get(reflectTest);        System.out.println(s);        //修改私有成员变量的值        field.set(reflectTest, "修改私有方法");        //打印私有参数的值        System.out.println(reflectTest.getTestPrivateFiled());    }

运行结果:

私有参数默认值私有参数默认值修改私有方法进程完成,退出码 0

可以看到我们已经成功通过反射修改了私有成员变量的值,关于通过反射修改公共成员变量我就不写了。

接下来我们看一下通过反射调用私有的方法testPrivateMethod():

    public static void main(String[] args) throws Exception {        //获取类        Class c = Class.forName("com.shenhesoft.lib.ReflectTest");        //创建一个对象        ReflectTest reflectTest = new ReflectTest("公共参数默认值", "私有参数默认值");        //获取私有的方法        Method method = c.getDeclaredMethod("testPrivateMethod", null);        //设置可以访问私有的成员方法,重要        method.setAccessible(true);        //调用私有方法        method.invoke(reflectTest, null);    }

运行结果:

私有方法进程完成,退出码 0

结果就不用多说了,接下来我们再看一下带有参数的公共方法怎么调用:

   public static void main(String[] args) throws Exception {        //获取类        Class c = Class.forName("com.shenhesoft.lib.ReflectTest");        //创建一个对象        ReflectTest reflectTest = new ReflectTest("公共参数默认值", "私有参数默认值");        //获取公共的方法        Method method = c.getMethod("testPublicMethod", String.class);        //调用公共方法        method.invoke(reflectTest, "反射");    }

运行结果:

公共方法,参数:反射进程完成,退出码 0

然后还有重要的一个操作,反射获取私有的静态成员变量和调用私有的静态方法,我们都知道静态的属性是类加载器启动的时候就已经加载了,并且全局只有一个,那我们获取的时候还需要对象吗,显然是不需要的,下面是具体的代码:
先在ReflectTest类中添加静态成员变量和方法

public class ReflectTest {    public String testPublicFiled;    private String testPrivateFiled;    private static String testStaticFiled;    public ReflectTest() {    }    public ReflectTest(String testPublicFiled, String testPrivateFiled) {        this.testPublicFiled = testPublicFiled;        this.testPrivateFiled = testPrivateFiled;    }    public void testPublicMethod(String name) {        System.out.println("公共方法,参数:" + name);    }    private void testPrivateMethod() {        System.out.println("私有方法");    }    public String getTestPublicFiled() {        return testPublicFiled;    }    public String getTestPrivateFiled() {        return testPrivateFiled;    }    public static String getTestStaticFiled() {        return testStaticFiled;    }    private static void testStatic() {        System.out.println("调用私有static方法");    }}
    public static void main(String[] args) throws Exception {        //获取类        Class c = Class.forName("com.shenhesoft.lib.ReflectTest");        Method method = c.getDeclaredMethod("testStatic", null);        method.setAccessible(true);        method.invoke(null, null);    }

运行结果:

调用私有static方法进程完成,退出码 0

获取并修改静态成员变量的值

    public static void main(String[] args) throws Exception {        //获取类        Class c = Class.forName("com.shenhesoft.lib.ReflectTest");        Field field = c.getDeclaredField("testStaticFiled");        field.setAccessible(true);        field.set(null, "修改静态的成员变量");        System.out.println(ReflectTest.getTestStaticFiled());    }
修改静态的成员变量进程完成,退出码 0

最后在补充一个反射有参数方法的例子:

Class mClass=m.getClass();Method method=mClass.getDeclaredMethod("setDrawerViewOffset",new Class[]{View.class,float.class});method.invoke(m,m,0.9);

方法名为:setDrawerViewOffset;
参数类型为:VIew,float;
调用该方法时传入实例m,以及参数m(View类型),0.9(float类型);

反射私有成员变量

Class mClass=m.getClass();//通过name获取成员变量mMinDrawerMarginField field=mClass.getDeclaredField("mMinDrawerMargin");//设置私有变量可以修改field.setAccessible(true);//获取成员变量的值Object value= field.get(m);//mMinDrawerMargin原来的值Log.i("info",value.toString());//修改成员变量的值           field.set(m,300);//获取修改之后成员变量的值value=field.get(m);//mMinDrawerMargin修改之后的值Log.i("info",value.toString());

top:访问所有private类型的变量、方法都要设置setAccessible(true);

参考自:https://blog.csdn.net/sinat_38259539/article/details/71799078

更多相关文章

  1. android中px,dp,sp的区别与使用方法
  2. Android核心分析 之一--------分析方法论探讨之设计意图
  3. android 设置颜色的三种方法
  4. android 获取设备支持的编解码器的方法
  5. Android Studio:Error:Could not find com.android.tools.build:g

随机推荐

  1. Android(安卓)断点续传
  2. android 手电筒demo
  3. android Thread和Runnable的区别
  4. android 古怪问题解决集合
  5. Android动态改变TextView字体颜色
  6. android 获取IP
  7. Android圆形进度条
  8. android NinePatchDrawable 9.png图片使
  9. android 怎样用代码设置墙纸
  10. android使用属性动画执行抖动效果