getXXX & getDeclaredXXX
getFields() 方法只能获得某个类及其父类中的所有的 public 字段,而 getDeclaredFields() 方法却能获得某个类(不包括父类)的所有字段(包括 public、private、proteced )等。
同样类似的还有 getConstructors() 和 getDeclaredConstructors()、getMethods() 和 getDeclaredMethods() 方法对。
测试类
public class ReflectClass {
public static final Integer FINAL_INTEGER = 1000;
public static final int FINAL_INT = 1000;
public static final String FINAL_STRING = "1000";
private int mCount;
private String mText;
ReflectClass() {
mCount = 1000;
mText = "reflect without param";
}
private ReflectClass(int count, String text) {
mCount = count;
mText = text;
}
private void printText(String text) {
Log.d("ReflectClass", text);
}
public int getCount() {
return mCount;
}
public String getText() {
return mText;
}
}
反射构造函数
private void testReflectConstructor() {
try {
Class reflectClass = Class.forName("com.example.javaproject.reflect.ReflectClass");
// 反射获取默认构造函数
Constructor constructor = reflectClass.getDeclaredConstructor();
// 获取对象实例
ReflectClass reflectObject = (ReflectClass) constructor.newInstance();
Log.d(TAG, "testReflectConstructor, count is " + reflectObject.getCount() + ", text is " + reflectObject.getText());
// 反射获取带参数构造函数
constructor = reflectClass.getDeclaredConstructor(int.class, String.class);
// 由于带参数的构造函数是private的,所以需要设置为accessible的
constructor.setAccessible(true);
reflectObject = (ReflectClass) constructor.newInstance(1001, "reflect with param");
Log.d(TAG, "testReflectConstructor, count is " + reflectObject.getCount() + ", text is " + reflectObject.getText());
} catch (Exception e) {
e.printStackTrace();
}
}
打印结果为:
testReflectConstructor, count is 1000, text is reflect without param
testReflectConstructor, count is 1001, text is reflect with param
反射方法
private void testReflectMethod() {
Class reflectClass = ReflectClass.class;
try {
Method method = reflectClass.getDeclaredMethod("printText", String.class);
method.setAccessible(true);
// 反射获取对象实例
ReflectClass reflectObject = (ReflectClass) reflectClass.newInstance();
method.invoke(reflectObject, "Hello, reflect method.");
} catch (Exception e) {
e.printStackTrace();
}
}
打印结果为:
Hello, reflect method.
反射字段
private void testReflectField() {
Class reflectClass = ReflectClass.class;
try {
ReflectClass reflectObject = (ReflectClass) reflectClass.newInstance();
Log.d(TAG, "testReflectField: before modify, mCount = " + reflectObject.getCount());
// 反射获取字段
Field field = reflectClass.getDeclaredField("mCount");
field.setAccessible(true);
// 修改值
field.set(reflectObject, 2000);
Log.d(TAG, "testReflectField: after modify, mCount = " + reflectObject.getCount());
} catch (Exception e) {
e.printStackTrace();
}
}
打印结果为:
testReflectField: before modify, mCount = 1000
testReflectField: after modify, mCount = 2000
反射常量字段
private void testConstantField() {
Class reflectClass = ReflectClass.class;
try {
Field fieldInteger = reflectClass.getDeclaredField("FINAL_INTEGER");
// 无法直接修改一个final的常量
// fieldInteger.set(null, 2000);
// 修改final常量的方法,去掉final限定符
Field modifiersField = Field.class.getDeclaredField("accessFlags");
modifiersField.setAccessible(true);
modifiersField.setInt(fieldInteger, fieldInteger.getModifiers() & ~Modifier.FINAL);
fieldInteger.set(null, 2000);
Integer modified_integer = (Integer) fieldInteger.get(null);
Log.d(TAG, "testConstantField: FINAL_INTEGER = " + ReflectClass.FINAL_INTEGER + ", modified_integer = " + modified_integer);
Field fieldInt = reflectClass.getDeclaredField("FINAL_INT");
modifiersField.setInt(fieldInt, fieldInt.getModifiers() & ~Modifier.FINAL);
fieldInt.set(null, 2000);
int modified_int = (int) fieldInt.get(null);
Log.d(TAG, "testConstantField: FINAL_INT = " + ReflectClass.FINAL_INT + ", modified_int = " + modified_int);
Field fieldString = reflectClass.getDeclaredField("FINAL_STRING");
modifiersField.setInt(fieldString, fieldString.getModifiers() & ~Modifier.FINAL);
fieldString.set(null, "2000");
String modified_string = (String) fieldString.get(null);
Log.d(TAG, "testConstantField: FINAL_STRING = " + ReflectClass.FINAL_STRING + ", modified_string = " + modified_string);
} catch (Exception e) {
e.printStackTrace();
}
}
打印结果为:
testConstantField: FINAL_INTEGER = 2000, modified_integer = 2000
testConstantField: FINAL_INT = 1000, modified_int = 2000
testConstantField: FINAL_STRING = 1000, modified_string = 2000
从结果上来看,我们的反射修改都成功了,但是ReflectClass这个类里面只有FINAL_INTEGER
真正被修改了。原因是当我们定义基本类型的 final 常量或者 String 类型的 final 常量时(只要为 final,不限制有无 static),如果在编译时能确定其确切值则编译器会将其用到的地方用其实际值进行替换,所以即便运行时反射成功也没有任何意义,因为相关值已经在编译时被替换为了常量,而对于包装类型则没事。
测试内部类
public class OuterClass {
private Runnable mRunnable = new Runnable() {
@Override
public void run() {
Log.d("AnonymousInnerClass", "I'm anonymous InnerClass");
}
};
private static class StaticInnerClass {
private String mText;
public StaticInnerClass(String text) {
mText = text;
}
public void print() {
Log.d("StaticInnerClass", "print: " + mText);
}
}
private class NormalInnerClass {
private String mText;
public NormalInnerClass(String text) {
mText = text;
}
public void print() {
Log.d("NormalInnerClass", "print: " + mText);
}
}
}
反射静态内部类
private void testStaticInnerClass() {
try {
Class innerClass = Class.forName("com.example.javaproject.reflect.OuterClass$StaticInnerClass");
Method printMethod = innerClass.getDeclaredMethod("print");
Object innerClassObject = innerClass.getDeclaredConstructor(String.class).newInstance("I'm static InnerClass");
printMethod.invoke(innerClassObject);
} catch (Exception e) {
e.printStackTrace();
}
}
打印结果为:
StaticInnerClass: print: I'm static InnerClass
反射内部类
private void testNormalInnerClass() {
try {
Class innerClass = Class.forName("com.example.javaproject.reflect.OuterClass$NormalInnerClass");
Method printMethod = innerClass.getDeclaredMethod("print");
OuterClass outerObject = OuterClass.class.newInstance();
// 构造函数的第一个参数要传入外部类对象
Object innerClassObject = innerClass.getDeclaredConstructor(OuterClass.class, String.class).newInstance(outerObject, "I'm normal InnerClass");
printMethod.invoke(innerClassObject);
} catch (Exception e) {
e.printStackTrace();
}
}
非静态内部类会隐式持有外部类的引用,就是在构造函数中引入的,所以反射非静态内部的时候需要将外部类对象作为第一个参数,否则会报NoSuchMethodException
的异常。相反,静态内部类不持有外部类的引用,所以构造函数不需要传入外部类对象。非静态内部类隐式持有外部类也是Android经常发生内存泄漏的原因之一。
反射匿名内部类
// 匿名内部类直接当成外部类的成员变量去反射就好了
private void testAnonymousInnerClass() {
try {
Class outerClass = OuterClass.class;
Field field = outerClass.getDeclaredField("mRunnable");
field.setAccessible(true);
Runnable runnable = (Runnable) field.get(outerClass.newInstance());
runnable.run();
} catch (Exception e) {
e.printStackTrace();
}
}
打印结果为:
AnonymousInnerClass: I'm anonymous InnerClass
网友评论