反射机制

反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用反射机制来实现对自己行为的描述和监测,并能根据自身行为的状态和结果,修改应用所描述行为的状态和相关的语义。
在Java中的反射机制,被称为Reflection。它允许运行中的Java程序对自身进行检查,并能直接操作程序的内部属性或方法。Reflection机制允许程序在正在执行的过程中,利用Reflection API取得任何已知名称的类的内部信息,包括:package、 superclass、 inner classes、 fields、 constructors、 methods、 modifiers等,并可以在执行的过程中,动态生成实例或调用某个方法。
Android中的一些源码所提供的对外接口有时并不能满足我们的一些设置,当有时我们需要做自定义的个性化组件等开发时是受限制的,这时,我们就可以采用这种反射机制访问存在访问权限的方法或修改其域。
这里我们提供一个测试类,用来后面分析反射过程

package mainpackage;

import java.io.Serializable;

/**
 * 用于测试的反射类
 *
 * @since 2016
 */
public class ReflectClass extends Object implements Serializable {

    private int count;
    private String entity = "";
    public static boolean isOk;

    public ReflectClass() {

    }

    public ReflectClass(Integer id, String name) {

    }

    private ReflectClass(String s) {

    }

    public static Integer method(Boolean d, String s) {
        return 0;
    }

    protected void staticMethod() {

    }
}

反射机制中的类

Java的类反射所需要的类并不多,它们分别是:Field、Constructor、Method、Class、Object,下面我将对这些类做一个简单的说明。

Class

Class本身就是一个类,Class是该类的名称,Class类是整个Java反射机制的源头,Class类本身表示Java对象的类型,我们可通过一个Object对象的getClass()方法取得一个对象的类型,此函数返回的就是一个Class类。

Object

每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。

Method

提供关于类或接口上某个方法的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。 这个类不难理解,它是用来封装反射类方法的一个类。

Field

提供有关类或接口的属性的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)属性或实例属性,简单的理解可以把它看成一个封装反射类的属性的类。

Constructor

提供关于类的单个构造方法的信息以及对它的访问权限。这个类和Field类不同,Field类封装了反射类的属性,而Constructor类则封装了反射类的构造方法。


获取重要类

获取重要类的反射机制都依赖Class这个类,Class类是整个Java反射机制的源头

获取Class类

获取Class对象的方法有很多种

1. object.getClass()
每一个Class都具备这个方法,所以可以通过这个方式获取到对应类

ReflectClass refClass = new ReflectClass();
Class clazz = refClass.getClass();
System.out.println("获取到类名:"+ clazz.getName());


2. Class.forName()
这种方式可以直接通过类的名称取得Class类的对象,在开发过程中很多应用,比如jdbc中驱动的注册等

try {
     Class clazz = Class.forName("mainpackage.ReflectClass");
     System.out.println("获取到类名:"+ clazz.getName());

} catch (ClassNotFoundException e) {
            e.printStackTrace();
}


3. .class属性
通过Class.class方式直接获得对应的类

Class clazz = ReflectClass.class;
System.out.println("获取到类名:" + clazz.getName());


以上几种方式都能够灵活的获取到对应的Class类,当我们得到Class的对象之后就可以通过反射的方法做很多事情


获取Constructor类

获取构造器的方法:在Class类中提供的方法

有四种方式
1. Constructor getConstructors() — 返回所有具有public属性的构造函数数组
2. Constructor getDeclaredConstructors() — 返回该类中所有的构造函数数组(不分public和非public属性)
3. Constructor getConstructor(Class[] params) — 根据构造函数的参数,返回一个具体的具有public属性的构造函数
4. Constructor getDeclaredConstructor(Class[] params) — 根据构造函数的参数,返回一个具体的构造函数(不分public和非public属性)

一个类中或许存在多种构造函数,可以选用上面的某种方式得到想要的构造函数

public class MainClass {

    public static void main(String[] args) throws ClassNotFoundException {
        ReflectClass refClass = new ReflectClass();
        Class clazz = refClass.getClass();

        //获取public构造函数
        Constructor[] con1 = clazz.getConstructors();
        write(con1.toString());
        //获取所有构造方法
        Constructor[] con2 = clazz.getDeclaredConstructors();
        write(con2.toString());
        //获取特定的构造方法
        try {
            Constructor con3 = clazz.getConstructor(Integer.class,String.class);
            write(con3.toString());

            Constructor con4 = clazz.getDeclaredConstructor(String.class);
            write(con4.toString());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
    public static void write(String s){
        System.out.println(s);
    }
}

得到输出的结果:
[Ljava.lang.reflect.Constructor;@4d1b92ef
[Ljava.lang.reflect.Constructor;@242df8f8
public mainpackage.ReflectClass(java.lang.Integer,java.lang.String)
private mainpackage.ReflectClass(java.lang.String)

可以看到都获取到了对应的构造方法


获取Method类

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

有四种方法
Method getMethod(String name, Class[] params) — 根据方法名和参数,返回一个具体的具有public属性的方法
Method[] getMethods() — 返回所有具有public属性的方法数组,包括从父类继承的public方法和实现接口的public方法
Method getDeclaredMethod(String name, Class[] params) — 根据方法名和参数,返回一个具体的方法(不分public和非public属性)
Method[] getDeclaredMethods() — 返回该类中的所有的方法数组(不区分public和非public属性),这里不包括从父类继承的方法。

这里要注意,有参数的两个方法中方法名字和参数必须和类中的相吻合,否则会抛出异常没有找到该方法

public class MainClass {

    public static void main(String[] args) throws ClassNotFoundException {
        ReflectClass refClass = new ReflectClass();
        Class clazz = refClass.getClass();

        //获取public方法
        Method[] con1 = clazz.getMethods();
        write(con1.toString());
        //获取所有方法
        Method[] con2 = clazz.getDeclaredMethods();
        write(con2.toString());
        //获取特定的方法
        try {
            Method con3 = clazz.getMethod("method",Boolean.class,String.class);
            write(con3.toString());

            Method con4 = clazz.getDeclaredMethod("staticMethod",null);
            write(con4.toString());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
    public static void write(String s){
        System.out.println(s);
    }
}

运行后得到结果
[Ljava.lang.reflect.Method;@99ffac2
[Ljava.lang.reflect.Method;@2d09b23b
public java.lang.Integer mainpackage.ReflectClass.method(java.lang.Boolean,java.lang.String)
protected static void mainpackage.ReflectClass.staticMethod()


获取Field类

获取Field的方法:在Class类中提供的方法,这个方法是获取类的成员变量

四种方式
Field getField(String name) — 根据变量名,返回一个具体的具有public属性的成员变量
Field[] getFields() — 返回具有public属性的成员变量的数组
Field getDeclaredField(String name) — 根据变量名,返回一个成员变量(不分public和非public属性)
Field[] getDelcaredField() — 返回所有成员变量组成的数组(不分public和非public属性)

这里的参数信息要和成员变量的名字一样,而且要注意是否是public的从而选定获取方法

public class MainClass {

    public static void main(String[] args) throws ClassNotFoundException {
        ReflectClass refClass = new ReflectClass();
        Class clazz = refClass.getClass();

        //获取public方法
        Field[] con1 = clazz.getFields();
        write(con1.toString());
        //获取所有方法
        Field[] con2 = clazz.getFields();
        write(con2.toString());
        //获取特定的方法
        try {
            Field con3 = clazz.getField("isOk");
            write(con3.toString());

            Field con4 = clazz.getDeclaredField("count");
            write(con4.toString());
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
    public static void write(String s){
        System.out.println(s);
    }
}

可以看到输出结果
[Ljava.lang.reflect.Field;@5f2679f2
[Ljava.lang.reflect.Field;@57102fab
public static boolean mainpackage.ReflectClass.isOk
private int mainpackage.ReflectClass.count


获取相关信息


Class类的方法

这里还是通过开始给出的示例 java 程序来做演示,以下的 clazz 都是通过上述方式获取到的Class对象
Class类有很多方法

  • public T newInstance() :根据对象的class新建一个对象,用于反射。非常重要。
  • public String getName() :获取类或接口的名字
  • public Package getPackage() :反射中获得package
  • public native int getModifiers() : 反射中获得修饰符,如public static void等
  • public boolean isEnum() :判断是否为枚举类型
  • public native boolean isArray() :判断是否为数组类型
  • public native boolean isPrimitive() :判断是否为基本类型
  • public ClassLoader getClassLoader() :获得类的类加载器

除了这些方法还有以上那些获得类中成员、方法和构造方法的方法

下面详细看几个方法用法:
1. 获取类的包名和类名

获取包名:clazz. getPackage().getName()
获取类名:clazz. getName()

这两个方法都比较简单,我们看一下代码和返回到结果

/**
 * 调用主类
 */
public class MainClass {

    public static void main(String[] args) throws ClassNotFoundException {
        ReflectClass refClass = new ReflectClass();
        Class clazz = refClass.getClass();
        System.out.println(clazz.getPackage().getName() + "---" + clazz.getName());
    }
}

执行后返回到结果是:mainpackage—mainpackage.ReflectClass


2. 获取修饰符

获取修饰类型:int getModifiers()

这个是 Class、Method、Constructor、Field都有一个public方法,用来得到修饰类型比如 public、private、static、final、native、synchronize、volatile等。这里还提供了 Modifier.toString(int modifier) 方法将int数转换成描述修饰符的字符串

public class MainClass {

    public static void main(String[] args) throws ClassNotFoundException {
        ReflectClass refClass = new ReflectClass();
        Class clazz = refClass.getClass();
        int modifier = clazz.getModifiers();
        System.out.println("得到修饰符:"+Modifier.toString(modifier));
    }
}

执行后得到输出为 得到修饰符:public


Constructor类的方法

下面我们看一下Constructor类中提供的一些方法

  • public String getName() :获取构造器的名字
  • public native int getModifiers() : 反射中获得修饰符,如public static void等
  • Class< ? > [] getParameterTypes():获得参数的属性
  • newInstance(Object… initargs):使用构造器创建实例

我们通过一段代码看一下这些方法,以下这段代码显示ReflectClass类中所有的构造方法

/**
 * @since 2016
 */
public class MainClass {
    private Class clazz;

    public static void main(String[] args) {
        new MainClass().doSome();
    }

    public void doSome() {
        try {

            clazz = Class.forName("mainpackage.ReflectClass");
            Constructor[] cons = clazz.getDeclaredConstructors();

            for (int i = 0; i < cons.length; i++) {
                int modifier = cons[i].getModifiers();
                out(Modifier.toString(modifier) + " ");
                out(clazz.getName() + " ( ");
                Class[] types = cons[i].getParameterTypes();

                for (int j = 0; j < types.length; j++) {
                    String paramType = types[j].getName();
                    out(paramType + " " + paramType.toLowerCase());
                    if(j1){
                        out(",");
                    }
                }
                outln(")");

            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static void out(String s) {
        System.out.print(s);
    }

    public static void outln(String s) {
        System.out.println(s);
    }
}

然后我们可以看到执行后构造函数的样子

private mainpackage.ReflectClass ( java.lang.String java.lang.string)
public mainpackage.ReflectClass ( java.lang.Integer java.lang.integer,java.lang.String java.lang.string)
public mainpackage.ReflectClass ( )


Method类的方法

Method中也有很多自己的方法,我们来看一下

  • public String getName() :获取构造器的名字
  • public native int getModifiers() : 反射中获得修饰符,如public static void等
  • Class< ? > [] getParameterTypes():获得参数的属性
  • Class < ? > getReturnType():获得返回值的属性
  • invoke(Object obj, Object… args):obj对象执行这个方法,第一个参数为该方法的对象,第二个为参数

然后我们用下面这段代码将ReflectClass类中的method方法抽出来看看,然后用自己生成的ReflectClass对象执行这个方法

/**
 * @since 2016
 */
public class MainClass {
    private Class clazz;

    public static void main(String[] args) {
        new MainClass().doSome();
    }

    public void doSome() {
        try {
            clazz = Class.forName("mainpackage.ReflectClass");
            Method mMethod = clazz.getDeclaredMethod("method", Boolean.class, String.class);

            int modifer = mMethod.getModifiers();
            out(Modifier.toString(modifer));
            Class returnType = mMethod.getReturnType();
            out(" " + returnType.getName() + " " + mMethod.getName() + " (");
            Class[] paramType = mMethod.getParameterTypes();
            for (int i = 0; i < paramType.length; i++) {
                out(paramType[i].getName() + " " + paramType[i].getName().toLowerCase());
                if (i < paramType.length - 1) {
                    out(" , ");
                }
            }
            outln(" ) ");

            //产生一个ReflectClass对象执行这个方法
            Object reflectObj = clazz.newInstance();
            out(mMethod.invoke(reflectObj, new Object[]{new Boolean(true), "ok"}) + "");


        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    public static void out(String s) {
        System.out.print(s);
    }

    public static void outln(String s) {
        System.out.println(s);
    }
}

然后我们可以看到执行后得到的输出

public static java.lang.Integer method (java.lang.Boolean java.lang.boolean , java.lang.String java.lang.string )
0


Field类的方法

然后我们来看一下类中成员变量 Field 具备什么方法

  • boolean equals(Object other) : 返回是否是同一类
  • Object get(Object object) :返回这个对象的值
  • boolean getBoolean(Object object):如果是Boolean类型返回布尔值
    Field有很多方法,具体看API

下面我们取出ReflectClass中的entity成员变量进行操作

/**
 * @since 2016
 */
public class MainClass {
    private Class clazz;

    public static void main(String[] args) {
        new MainClass().doSome();
    }

    public void doSome() {
        try {
            clazz = Class.forName("mainpackage.ReflectClass");
            Field mField = clazz.getDeclaredField("entity");
            outln("得到成员:" + mField);

            Field mBooleanField = clazz.getField("isOk");
            ReflectClass ref = new ReflectClass();
            mBooleanField.setBoolean(ref.isOk, false);
            outln("更改后:" + mBooleanField.get(ref.isOk));


        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

    }

    public static void out(String s) {
        System.out.print(s);
    }

    public static void outln(String s) {
        System.out.println(s);
    }
}

我们可以看到运行出来之后的结果,还有很多具体的方法可以通过API查询

得到成员:private java.lang.String mainpackage.ReflectClass.entity
更改后:false

以上就是我们对反射机制的一点总结,在android中和java中的情况都是类似的,都是通过反射来更加灵活调用一些方法来满足我们的需求。

你可能感兴趣的:(java,api,应用,class,【Android,权限机制】)