文章目录
- 1 根据一个字符串得到一个类
- 1.1 getClass
- 1.2 Class.forName
- 1.3 class属性
- 1.4 TYPE属性
- 2 获取类的成员
- 2.1 类的构造函数
- 2.1.1 获取类的所有构造函数。
- 2.1.2 获取类的公共构造函数。
- 2.1.3 获取类的某个构造函数
- 2.1.4 调用构造函数
- 2.2 获取类的私有实例方法并调用它
- 2.3 获取类的静态的私有方法并调用它
- 2.4 获取类的私有实例字段并修改它
- 2.5 获取类的私有静态字段并修改它
- 3 对泛型类的反射(模拟系统源码)
下面介绍基本反射技术。
反射包括以下技术:
- 根据一个字符串得到一个类的对象。
- 获取一个类的所有公用或私有、静态或实例的字段、方法、属性。
- 对泛型类的反射。
1 根据一个字符串得到一个类
通过 Class 的 getName方法查看结果:
1.1 getClass
通过一个对象,获取它的类型。类型用Class表示:
//通过getClass,每个Class都有这个函数
String str = "abc";
Class c1 = str.getClass();
打印结果:
1.2 Class.forName
//这种方式最常见,通过静态方法Class.forName()
Class c2 = null;
Class c3 = null;
Class c5 = null;
//这种方式最常见,通过静态方法Class.forName()
try {
c2 = Class.forName("java.lang.String");
c3 = Class.forName("android.widget.Button");
//通过getSuperClass,每个Class都有这个函数
c5 = c3.getSuperclass(); //得到TextView
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
打印结果:
1.3 class属性
每个类都有class属性,可以得到这个类的类型:
//通过 .class属性
Class c6 = String.class;
Class c7 = java.lang.String.class;
Class c8 = MainActivity.InnerClass.class;
Class c9 = int.class;
Class c10 = int[].class;
打印结果:
1.4 TYPE属性
基本类型都有TYPE属性,可以得到这个基本类型的类型
//基本类型包装类的TYPE语法
Class c11 = Boolean.TYPE;
Class c12 = Byte.TYPE;
Class c13 = Character.TYPE;
Class c14 = Short.TYPE;
Class c15 = Integer.TYPE;
Class c16 = Long.TYPE;
Class c17 = Float.TYPE;
Class c18 = Double.TYPE;
Class c19 = Void.TYPE;
打印结果:
2 获取类的成员
2.1 类的构造函数
获取类的构造函数,包括private和public两种,也支持无参数和有参数两种类型的构造函数。
获取类的构造函数由以下两个方法完成:
- getDeclaredConstructors:获取所有构造函数
- getConstructors:获取公共构造函数
新建TestClassCtor 添加一些构造函数,如下:
public class TestClassCtor {
private int id;
private String name;
private static String address = "abc";
public TestClassCtor() {
id = 0;
name = "hongxue";
}
public TestClassCtor(int a) {
id = a;
}
public TestClassCtor(int a, String b) {
id = a;
name = b;
}
private TestClassCtor(int a, double c) {
}
private String doSomething(String d) {
Log.v("hongxue", "TestClassCtor, doSOmething");
return "abcd";
}
private static void work() {
Log.v("hongxue", "TestClassCtor, work");
}
public String getName() {
return name;
}
public static void printAddress() {
Log.v("hongxue", address);
}
public int getId() {
return id;
}
}
使用printCtor方法打印获取到的构造函数的 修饰域、方法名称、方法的参数,如下:
void printCtor(Constructor theConstructor) {
int mod = theConstructor.getModifiers();// 输出修饰域和方法名称
Log.v("hongxue", Modifier.toString(mod) + "(");
Class[] parameterTypes = theConstructor.getParameterTypes(); // 获取指定构造方法的参数的集合
for (int j = 0; j < parameterTypes.length; j++) { // 输出打印参数列表
Log.v("hongxue", parameterTypes[j].getName());
if (parameterTypes.length > j + 1) {
Log.v("hongxue", ", ");
}
}
Log.v("hongxue", ")");
}
使用printCtors打印多个构造方法,代码如下:
public static void printCtors(Constructor[] theConstructors,String className){
try {
for (int i = 0; i < theConstructors.length; i++) {
int mod = theConstructors[i].getModifiers();// 输出修饰域和方法名称
Log.v("hongxue", Modifier.toString(mod) + " " + className + "(");
Class[] parameterTypes = theConstructors[i].getParameterTypes();// 获取指定构造方法的参数的集合
for (int j = 0; j < parameterTypes.length; j++) { // 输出打印参数列表
Log.v("hongxue", parameterTypes[j].getName());
if (parameterTypes.length > j + 1) {
Log.v("hongxue", ", ");
}
}
Log.v("hongxue", ")");
}
}catch (Exception e) {
e.printStackTrace();
}
}
2.1.1 获取类的所有构造函数。
使用Class的getDeclaredConstructors方法获取类的所有ctor,不分public还是private:
TestClassCtor r = new TestClassCtor();
Class temp = r.getClass();
String className = temp.getName(); // 获取指定类的类名
Log.v("hongxue", "获取类的所有ctor,不分public还是private----------------------------------------------");
Constructor[] theCtorsAll = temp.getDeclaredConstructors(); // 获取指定类的所有构造方法
Util.printCtors(theCtorsAll,className);
打印结果如下:
从结果中可以看出:getDeclaredConstructors确实可以获取所有构造方法。
2.1.2 获取类的公共构造函数。
Log.v("hongxue", "获取类的public ctor----------------------------------------------");
Constructor[] theCtorsPublic = temp.getConstructors();//获取指定类的公共构造方法
Util.printCtors(theCtorsPublic,className);
打印结果:
2.1.3 获取类的某个构造函数
TestClassCtor r = new TestClassCtor();
Class temp = r.getClass();
//获取类的ctor:TestClassCtor()
Constructor c1 = temp.getDeclaredConstructor();
Util.printCtor(c1);
//获取类的ctor:TestClassCtor(int a)
Class[] p2 = {int.class};
Constructor c2 = temp.getDeclaredConstructor(p2);
Util.printCtor(c2);
//获取类的ctor:TestClassCtor(int a, String b)
Class[] p3 = {int.class, String.class};
Constructor c3 = temp.getDeclaredConstructor(p3);
Util.printCtor(c3);
//获取类的ctor:TestClassCtor(int a, double c)
Class[] p4 = {int.class, double.class};
Constructor c4 = temp.getDeclaredConstructor(p4);
Util.printCtor(c4);
查看打印结果:
反射到类的构造函数很重要:通过字符串反射出一个类,然后通过反射获取到类的构造函数,执行构造函数就得到了类的实例。有了实例就可以通过反射进一步得到实例的所有字段和方法。
2.1.4 调用构造函数
通过反射调用构造函数,得到类的实例,这里借助于Constructor的newInstance方法:
//通过反射,获取一个类的ctor,然后调用它
try {
Class r = Class.forName("com.hongx.reflection.TestClassCtor");
//含参
Class[] p3 = {int.class, String.class};
Constructor ctor = r.getDeclaredConstructor(p3);
Object obj = ctor.newInstance(1, "fhx");//修改了id和name的值
TestClassCtor t = (TestClassCtor)obj;
Log.w(TAG,"id = " + t.getId() + " name = "+ t.getName());
//无参
Constructor ctor2 = r.getDeclaredConstructor();
Object obj2 = ctor2.newInstance();
TestClassCtor t2 = (TestClassCtor)obj2;
Log.w(TAG,"id = " + t2.getId() + " name = "+ t2.getName());//得到的id和name都是默认值
//也可以使用Class的newInstance方法,但Class仅提供默认无参的实例化方法
Object obj4 = r.newInstance();
TestClassCtor t4 = (TestClassCtor)obj4;
Log.w(TAG,"id = " + t4.getId() + " name = "+ t4.getName());
} catch (Exception e) {
e.printStackTrace();
}
打印结果:
2.2 获取类的私有实例方法并调用它
在TestClassCtor中,有一个私有方法doSomething:
private String doSomething(String d) {
Log.v("hongxue", "TestClassCtor, doSomething");
return d;
}
//以下4句话,创建一个对象
Class r = Class.forName("com.hongx.reflection.TestClassCtor");
Constructor ctor2 = r.getDeclaredConstructor();
Object obj = ctor2.newInstance();
//以下4句话,调用一个private方法
Class[] p4 = {String.class};
Method method = r.getDeclaredMethod("doSomething", p4); //在指定类中获取指定的方法
method.setAccessible(true);
Object argList[] = {"hongxue123"}; //这里写死,下面有个通用的函数getMethodParamObject
Object result = method.invoke(obj, argList);
Log.v(TAG,result.toString());
打印:
2.3 获取类的静态的私有方法并调用它
在TestClassCtor中,有一个静态的私有方法work:
/**
* 在TestClassCtor中有一个私有的方法work
*/
private static void work() {
Log.v("hongxue", "TestClassCtor, work");
}
//以下4句话,创建一个对象
Class r = Class.forName("com.hongx.reflection.TestClassCtor");
//以下3句话,调用一个private静态方法
Method method = r.getDeclaredMethod("work"); //在指定类中获取指定的方法
method.setAccessible(true);
method.invoke(null);
打印结果:
V/hongxue: TestClassCtor, work
2.4 获取类的私有实例字段并修改它
在TestClassCtor中,有一个私有的实例字段name:
public class TestClassCtor {
private String name;
public String getName() {
return name;
}
}
//以下4句话,创建一个对象
Class r = Class.forName("com.hongx.reflection.TestClassCtor");
Class[] p3 = {int.class, String.class};
Constructor ctor = r.getDeclaredConstructor(p3);
Object obj = ctor.newInstance(10, "fhx");
//获取name字段,private
Field field = r.getDeclaredField("name");
field.setAccessible(true);
Object fieldObject = field.get(obj);
Log.w(TAG,"name = " + fieldObject.toString() );
//只对obj有效
field.set(obj, "hongxue1988");//修改
Log.w(TAG,"name = " + field.get(obj).toString() );
//这次修改仅对当前这个对象有效,如果接下来我们再次创建一个TestClassCtor 对象,它的name字段的值为空
TestClassCtor testClassCtor = new TestClassCtor(100);
Log.w(TAG,"name = " + testClassCtor.getName() + " ; id = " + testClassCtor.getId()); //仍然返回null,并没有修改
打印结果:
2.5 获取类的私有静态字段并修改它
在TestClassCtor中,有一个静态的私有字段address:
//以下4句话,创建一个对象
Class r = Class.forName("com.hongx.reflection.TestClassCtor");
//获取address静态字段,private
Field field = r.getDeclaredField("address");
field.setAccessible(true);
Object fieldObject = field.get(null);
field.set(fieldObject, "ABCD");
//静态变量,一次修改,终生受用
TestClassCtor.printAddress();
打印结果:
与前面介绍的实例字段不同,静态字段的值被修改了,下次再使用,这个字段的值是修改后的值。所谓“一次修改,终生受用”。
3 对泛型类的反射(模拟系统源码)
Android系统源码中存在大量泛型,所以插件化技术离不开对泛型进行反射,比如单例模式(Singleton)。
以下代码是从Android源码中找出来的:
public abstract class Singleton<T> {
private T mInstance;
protected abstract T create();
public final T get() {
synchronized (this) {
if(mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}
Singleton 是一个泛型类,我们可以通过以下代码,取出Singleton中的mInstance字段 :
Class<?> singleton = Class.forName("com.hongx.reflection.Singleton");
Field mInstanceField = singleton.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
同时, Singleton也是一个抽象类,在实例化Singleton的时候,一定要实现 create 这个抽象方法 。
public interface ClassB2Interface {
void doSomething();
}
public class AMN {
private static final Singleton<ClassB2Interface> gDefault = new Singleton<ClassB2Interface>() {
protected ClassB2Interface create() {
ClassB2 b2 = new ClassB2();
b2.id = 2;
return b2;
}
};
static public ClassB2Interface getDefault() {
return gDefault.get();
}
}
class ClassB2 implements ClassB2Interface{
public int id;
public void doSomething() {
Log.v("hongxue", "ClassB2 doSomething");
}
}
ActivityManager am;
try {
// gDefault是一个 android.util.Singleton对象; 我们取出这个单例里面的字段
Class<?> singleton = Class.forName("com.hongx.reflection.Singleton");
Field mInstanceField = singleton.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
//获取AMN的gDefault单例gDefault,gDefault是静态的
Class<?> activityManagerNativeClass = Class.forName("com.hongx.reflection.AMN");
Field gDefaultField = activityManagerNativeClass.getDeclaredField("gDefault");
gDefaultField.setAccessible(true);
Object gDefault = gDefaultField.get(null);
// AMN的gDefault对象里面原始的 B2对象
Object rawB2Object = mInstanceField.get(gDefault);
// 创建一个这个对象的代理对象ClassB2Mock, 然后替换这个字段, 让我们的代理对象帮忙干活
Class<?> classB2Interface = Class.forName("com.hongx.reflection.ClassB2Interface");
Object proxy = Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class<?>[] { classB2Interface },
new ClassB2Mock(rawB2Object));
mInstanceField.set(gDefault, proxy);
} catch (Exception e) {
e.printStackTrace();
}