反射API
本文将按如下导图讲述反射的使用
Class对象的获取
方法一:
Class clazz = test.getClass();
方法二:
Class clazz = Test.class;
方法三:
try {
Class clazz = Class.forName("com.app.xz.classtest.Test");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
一般使用第三种:
- 不依赖Java对象、不用引入包,只需要传入字符串即可获取Class对象,可灵活配置。
- 即使类加上了@hide,也能通过这种方式在java虚拟机中去寻找这个类有没有被加载。
Class对象的使用
通过Class对象获取类名
class.getName();
示例:
Log.e(TAG, int.class.getName());
Log.e(TAG, String.class.getName());
Log.e(TAG, Test.class.getName());
//数组
int[] is = new int[3];
Log.e(TAG, is.getClass().getName());
String[] ss = new String[3];
Log.e(TAG, ss.getClass().getName());
Test[] ts = new Test[3];
Log.e(TAG, ts.getClass().getName());
//Logcat输出
int
java.lang.String
com.app.xz.testclass.Test
[I
[Ljava.lang.String;
[Lcom.app.xz.testclass.Test;
注意点:
- 基本数据类型返回数据类型名,类返回包名加类名全路径。
- '['表示数组维度,如二维数组为'[['。
- '['后的大写字母表示当前数据类型关键字,映射关系如下所示:
数据类型 | 关键字 |
---|---|
int | I |
long | J |
short | S |
float | F |
boolean | Z |
byte | B |
char | C |
double | D |
类、接口 | L |
通过Class对象获取类的修饰符
int modifiers = clazz.getModifiers();
Modifier.toString(modifiers);
Modifier.isPublic(modifiers);
//Modifier.toString的输出结果如:
public abstract
通过Class对象获取类的成员变量Field
获取指定名字的Field
public Field getDeclaredField(String name)
throws NoSuchFieldException,
SecurityException;
public Field getField(String name)
throws NoSuchFieldException,
SecurityException
获取所有Field
public Field[] getDeclaredFields() throws SecurityException {}
public Field[] getFields() throws SecurityException {
下面通过测试代码解析getFields
和getDeclaredFields
的区别
测试代码1:
//Bean类
public class Child {
int a = 0;
private int b = 1;
protected int c = 2;
public int d = 3;
}
//测试代码
Class clazz = Child.class;
for (Field field : clazz.getFields()) {
Log.e(TAG, field.getName());
}
for (Field field : clazz.getDeclaredFields()) {
Log.e(TAG, field.getName());
}
//getFields输出
d
//getDeclaredFields输出
a
b
c
d
测试代码2:
//Bean类
public class Child extends Father{}
public class Father {
int a = 0;
private int b = 1;
protected int c = 2;
public int d = 3;
}
//测试代码
Class clazz = Child.class;
for (Field field : clazz.getFields()) {
Log.e(TAG, field.getName());
}
for (Field field : clazz.getDeclaredFields()) {
Log.e(TAG, field.getName());
}
//getFields输出
d
//getDeclaredFields无输出
结论:
getFields
获得所有 public 修饰的成员变量,包括父类。
getDeclaredFields
获得所有成员变量,但不包括父类。
下面是Field的用法。
通过Field获取成员变量的类型
public Type getGenericType() {}
public Class<?> getType() {}
区别参照测试代码
//Bean类
public class Child<T> {
public int a;
public T data;
public List<String> strings;
public Test test;
}
//测试代码
for (Field field : clazz.getDeclaredFields()) {
Log.e(TAG, field.getName());
Log.e(TAG, field.getGenericType().toString());
Log.e(TAG, field.getType().getName());
Log.e(TAG, "");
}
//输出结果
a
int
int
data
T
java.lang.Object
strings
java.util.List<java.lang.String>
java.util.List
test
class com.app.xz.testclass.Test
com.app.xz.testclass.Test
通过Field获取成员变量的修饰符
同class
public int getModifiers() {}
通过Field对成员变量执行get、set
Field是类的抽象成员变量,不涉及对象。
如果要对某对象的成员变量进行读取和赋值,需要传入对象。
如'鸟'类有'羽毛'这个成员变量,则'羽毛'代表一个Field。对于鸟A,'羽毛'这个Field是白色;对于鸟B,'羽毛'这个Field是花色。即Field代表类中的一个成员变量,它的取值和赋值需要对象才有意义。
get
public Object get(Object obj);
public int getInt(Object obj);
public long getLong(Object obj)
throws IllegalArgumentException, IllegalAccessException;
public float getFloat(Object obj)
throws IllegalArgumentException, IllegalAccessException;
public short getShort(Object obj)
throws IllegalArgumentException, IllegalAccessException;
public double getDouble(Object obj)
throws IllegalArgumentException, IllegalAccessException;
public char getChar(Object obj)
throws IllegalArgumentException, IllegalAccessException;
public byte getByte(Object obj)
throws IllegalArgumentException, IllegalAccessException;
public boolean getBoolean(Object obj)
throws IllegalArgumentException, IllegalAccessException
set
public void set(Object obj, Object value);
public void setInt(Object obj,int value);
public void setLong(Object obj,long value)
throws IllegalArgumentException, IllegalAccessException;
public void setFloat(Object obj,float value)
throws IllegalArgumentException, IllegalAccessException;
public void setShort(Object obj,short value)
throws IllegalArgumentException, IllegalAccessException;
public void setDouble(Object obj,double value)
throws IllegalArgumentException, IllegalAccessException;
public void setChar(Object obj,char value)
throws IllegalArgumentException, IllegalAccessException;
public void setByte(Object obj,byte b)
throws IllegalArgumentException, IllegalAccessException;
public void setBoolean(Object obj,boolean b)
throws IllegalArgumentException, IllegalAccessException
示例代码:
try {
Field f = Bird.class.getDeclaredField("feather");
//私有的成员变量,需要通过下面代码赋予操作权限
f.setAccessible(true);
//传入test对象以获取该对象的car成员变量
Feather feather = (Feather) f.get(bird);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
通过Class对象获取类的方法Method
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
public Method getMethod(String name, Class<?>... parameterTypes)
public Method[] getDeclaredMethods() throws SecurityException
public Method getMethod(String name, Class<?>... parameterTypes)
区别同上,getMethod
获得包括父类在内的所有 public 修饰的方法,getDeclaredMethods
获得所有方法,但不包括父类。
示例代码:
//Bean类
public class Child {
void sayDefault() {
}
private void sayPrivate() {
}
protected void sayProtect() {
}
public void sayPublic() {
}
}
//测试代码
Class clazz = Child.class;
for (Method method : clazz.getMethods()) {
Log.e(TAG, method.getName());
}
for (Method method : clazz.getDeclaredMethods()) {
Log.e(TAG, method.getName());
}
//getMethods输出结果
equals
getClass
hashCode
notify
notifyAll
sayPublic
toString
wait
wait
//getDeclaredMethods输出结果
sayPrivate
sayDefault
sayProtect
sayPublic
通过Method获取方法名
getName();
通过Method获取方法参数
public Parameter[] getParameters() {}
public Class<?>[] getParameterTypes() {}
public Type[] getGenericParameterTypes() {}
其中Paramter还可以获得参数的名字和修饰符:
// 获取参数名字
public String getName() {}
// 获取参数类型
public Class<?> getType() {}
// 获取参数的修饰符
public int getModifiers() {}
使用视情况而定。
通过Method获取方法返回值类型
// 获取返回值类型
public Class<?> getReturnType() {}
// 获取返回值类型包括泛型
public Type getGenericReturnType() {}
通过Method获取方法异常类型
public Class<?>[] getExceptionTypes() {}
public Type[] getGenericExceptionTypes() {}
通过Method获取方法修饰符
public int getModifiers() {}
通过Method执行方法
public Object invoke(Object obj, Object... args) {}
要点:
-
invoke() 方法中第一个参数 Object 实质上是 Method 所依附的 Class 对应的类的实例,如果这个方法是一个静态方法,那么 ojb 为 null,后面的可变参数 Object 对应的自然就是参数。
-
invoke() 返回的对象是 Object,所以实际上执行的时候要进行强制转换。
-
在对 Method 调用 invoke() 的时候,如果方法本身会抛出异常,那么这个异常就会经过包装,由 Method 统一抛出 InvocationTargetException。而通过 InvocationTargetException.getCause() 可以获取真正的异常。
示例代码:
//Bean类
public class Child {
private static void say(Context context, String text) {
Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
}
}
//测试代码
Class clazz = Child.class;
try {
Method say = clazz.getDeclaredMethod("say", Context.class, String.class);
say.setAccessible(true);
say.invoke(null, this, "six!");
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
通过反射的方式,可以调用Android一些私有的方法。
通过Class对象获取构造函数Constructor
参数为Class,表示构造函数参数的类型,无参可不传。
//获取指定构造函数
Constructor<T> constructor = class.getConstructor(Class<?>...params);
Constructor<T> constructor = class.getDeclaredConstructor(Class<?>...params);
//获取所有构造函数
Constructor<?>[] constructors = class.getConstructors();
Constructor<?>[] constructors = class.getDeclaredConstructors();
区别是:
getDeclaredConstructors
可以获取所有构造函数,但是不包括父类。
getConstructors
可以获得 public 修饰的所有构造函数,也不包括父类。
这里和Field、Method有所区别,Field、Method是可以获取到父类的 public 修饰的变量和方法的。
仔细想想:子类本来就可以调用父类的非私有成员变量和方法,但子类不能利用父类的构造函数初始化自己,反射也是基于此。
通过Constructor生成对象实例
获取对象有俩种方式:
方法一:利用class
class.newInstance();
方法二:利用constructor
constructor.setAccessible(true);
constructor.newInstance(Object...params);
区别是:
class.newInstance()
仅能通过非private的无参构造函数生成对象。
Constructor
上面说过,通过不同API,可以获取所有的构造函数,并通过构造函数生成对象。
通过Constructor获取构造函数参数类型
public Parameter[] getParameters() {}
public Class<?>[] getParameterTypes() {}
public Type[] getGenericParameterTypes() {}
通过Constructor获取构造函数异常类型
public Class<?>[] getExceptionTypes() {}
public Type[] getGenericExceptionTypes() {}
通过Constructor获取构造函数修饰符
public int getModifiers() {}
TOC
[TOC]