反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用反射机制来实现对自己行为的描述和监测,并能根据自身行为的状态和结果,修改应用所描述行为的状态和相关的语义。
在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类是整个Java反射机制的源头,Class类本身表示Java对象的类型,我们可通过一个Object对象的getClass()方法取得一个对象的类型,此函数返回的就是一个Class类。
每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。
提供关于类或接口上某个方法的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。 这个类不难理解,它是用来封装反射类方法的一个类。
提供有关类或接口的属性的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)属性或实例属性,简单的理解可以把它看成一个封装反射类的属性的类。
提供关于类的单个构造方法的信息以及对它的访问权限。这个类和Field类不同,Field类封装了反射类的属性,而Constructor类则封装了反射类的构造方法。
获取重要类的反射机制都依赖Class这个类,Class类是整个Java反射机制的源头
获取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的对象之后就可以通过反射的方法做很多事情
获取构造器的方法:在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 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的方法:在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
这里还是通过开始给出的示例 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类中提供的一些方法
- 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中也有很多自己的方法,我们来看一下
- 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 具备什么方法
- 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中的情况都是类似的,都是通过反射来更加灵活调用一些方法来满足我们的需求。