相关概念
简单说,JAVA反射机制是指在运行态可直接操作任意类或对象的所有属性和方法的功能。
反射用途
- 在运行时获取任意对象所属的类 Class<?> clazz = Class.forName(String className);
- 在运行时构造任意类的对象 Object obj = clazz.newInstance();
- 在运行时获取任意类所具有的成员变量和方法 field.set(Object obj, Object value);field.get(Object obj);
- 在运行时调用任意对象的方法 (最常见的需求,尤其是当该方法是私有方法或者隐藏方法)method.invoke(Object obj, Object... args);
反射还可以获取类的其他信息,包含modifiers(下面会介绍),以及superclass, 实现的interfaces等。 针对动态语言,大致认同的一个定义是:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。反射机制在运行时只能调用methods或改变fields内容,却无法修改程序结构或变量类型。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。
核心类
- java.lang.Class: 代表类
- java.lang.reflect.Constructor: 代表类的构造方法
- java.lang.reflect.Field: 代表类的属性
- java.lang.reflect.Method: 代表类的方法
- java.lang.reflect.Modifier:代表类、方法、属性的描述修饰符。其中Modifier取值范围如下: public, protected, private, abstract, static, final, transient, volatile, synchronized, native, strictfp, interface。
Constructor, Field, Method这三个类都继承AccessibleObject,该对象有一个非常重要的方法setAccessible(boolean flag), 借助该方法,能直接调用非Public的属性与方法。
核心方法
-
成员属性(Field):
- getFields():获得类的public类型的属性。
- getDeclaredFields():获得类的所有属性。
- getField(String name):获取当前类以及所有父类中的属性
- getDeclaredField(String name):获取类的特定属性
-
成员方法(Method)
- getMethods():获得类的public类型的方法。
- getDeclaredMethods():获得类的所有方法。
- getMethod(String name, Class[] parameterTypes):获得当前类或者所有父类的特定方法
- getDeclaredMethod(String name, Class[] parameterTypes):获得类的特定方法
-
构造方法(Constructor)
- getConstructors():获得类的public类型的构造方法。
- getDeclaredConstructors():获得类的所有构造方法。
- getConstructor(Class[] parameterTypes):获得当前类或者所有父类的特定构造方法
- getDeclaredConstructor(Class[] params);获得类的特定方法
深入Class类
Java所有的类都是继承于Oject类,其内声明了多个应该被所有Java类覆写的方法:hashCode()、equals()、clone()、toString()、notify()、wait()、getClass()等,其中getClass返回的便是一个Class类的对象。Class类也同样是继承Object类,拥有相应的方法。 Java程序在运行时,运行时系统对每一个对象都有一项类型标识,用于记录对象所属的类。虚拟机使用运行时类型来选择相应方法去执行,保存所有对象类型信息的类便是Class类。 Class类没有公共构造方法,Class对象是在加载类时由 Java 虚拟机以及通过调用ClassLoader的defineClass 方法自动构造的,因此不能显式地声明一个Class对象。 虚拟机为每种类型管理一个独一无二的Class对象。也就是说,每个类(型)都有一个Class对象。运行程序时,Java虚拟机(JVM)首先检查是否所要加载的类对应的Class对象是否已经加载。如果没有加载,JVM就会根据类名查找.class文件,并将其Class对象载入。 基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也都对应一个 Class 对象。 每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。一般某个类的Class对象被载入内存,它就用来创建这个类的所有对象。
用法
- 如何通过反射获取一个类?

- 私有类: 通过getDeclaredConstructor获取constructor,再调用constructor.setAccessible(true);
- 私有方法:通过getDeclaredMethod获取method,再调用method.setAccessible(true);
- 私有属性:通过getDeclaredField获取field,再调用field.setAccessible(true);
- @hide标记是做什么的,反射能否调用@hide标记的类: 在Android的源码中,我们会发现有很多被”@hide”标记的类,它的作用是使这个类或方法在生成SDK时不可见。那么应用程序便不可以直接调用。而反射机制可调用@hide标记的类或方法,如入无人之地,畅通无阻。
- 如何通过反射调用内部类? 假设com.reflect.Outer类有一个内部类inner,调用方法如下:
String className = "com.reflect.Outer$inner";
Class.forName(className);
实用
- 获取class类:获取class类可以通过四种方式获取
- 通过对象的getClass方式
- 通过Class.forName方式:这个方法用的最多
- 通过类的class属性
- 基本类型的TYPE属性
public void test1() {
//通过getClass,每个Class都有这个函数
String str = "abc";
Class c1 = str.getClass();
//这种方式最常见,通过静态方法Class.forName()
try {
Class c2 = Class.forName("java.lang.String");
Class c3 = Class.forName("android.widget.Button");
//通过getSuperClass,每个Class都有这个函数
Class c5 = c3.getSuperclass(); //得到TextView
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//通过.class属性
Class c6 = String.class;
Class c7 = java.lang.String.class;
Class c8 = MainActivity.InnerClass.class;
Class c9 = int.class;
Class c10 = int[].class;
//基本类型包装类的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;
}
-
获取类的构造函数:通过class的getDeclaredConstructors方法,获取类的所有构造函数,包括public和private,其中getConstructors则是获取public构造函数。这两个方法是获得所有的(前者为public+private所有,后者为public所有),那么如何获取某一特定的呢
-
获取无参的构造函数Constructor c1 = gotClass.getDeclaredConstructor 获取有一个参数,参数类型为int的构造函数 Class[] p2 = {int.class}; Constructor c2 = temp.getDeclaredConstructor(p2);
-
获取有两个参数,参数类型依次为int和string Class[] p3 = {int.class, String.class}; Constructor c3 = temp.getDeclaredConstructor(p3);
-
-
调用构造函数:需要通过反射调用构造函数得到类的实例,这要借助Constructor的newInstance方法
public void test2_1() {
//通过反射,获取一个类的ctor,然后调用它
try {
Class r = Class.forName("com.mwy.testreflection.TestClassCtor");
//含参
Class[] p3 = {int.class, String.class};
Constructor ctor = r.getDeclaredConstructor(p3);
Object obj = ctor.newInstance(1, "mwy");
//无参
Constructor ctor2 = r.getDeclaredConstructor();
Object obj2 = ctor2.newInstance();
//也可以使用Class的newInstance方法,但Class仅提供默认无参的实例化方法
Object obj4 = r.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
- 获取类的私有方法并调用,比如在TestClassCtor中有一个私有方法doSOmething
private String doSOmething(String d) {
Log.v("test", "TestClassCtor, doSOmething");
return "abcd";
}
要获取这个私有方法并执行他,要如下实现
//以下4句话,创建一个对象
Class r = Class.forName("com.mwy.testreflection.TestClassCtor");
Class[] p3 = {int.class, String.class};
Constructor ctor = r.getDeclaredConstructor(p3);
Object obj = ctor.newInstance(1, "bjq");
//以下3句话,调用一个private方法
Class[] p4 = {String.class};
Method method = r.getDeclaredMethod("doSOmething", p4); //在指定类中获取指定的方法
method.setAccessible(true);
Object argList[] = {"mwy"}; //这里写死,下面有个通用的函数getMethodParamObject
Object result = method.invoke(obj, argList);
- 获取类的静态私有方法并调用,比如在TestClassCtor中有一个静态私有方法work
private static void work() {
Log.v("test", "TestClassCtor, work");
}
要想获取这个静态的私有方法并执行它,需要如下代码
Class r = Class.forName("com.mwy.testreflection.TestClassCtor");
//以下3句话,调用一个private静态方法
Method method = r.getDeclaredMethod("work"); //在指定类中获取指定的方法
method.setAccessible(true);
method.invoke(null);
- 获取类的私有实例字段并修改它,比如在TestClassCotr中有一个字段private Sting name;想获取并修改这个字段的代码如下
//以下4句话,创建一个对象
Class r = Class.forName("com.mwy.testreflection.TestClassCtor");
Class[] p3 = {int.class, String.class};
Constructor ctor = r.getDeclaredConstructor(p3);
Object obj = ctor.newInstance(1, "mwy");
//获取name字段,private
Field field = r.getDeclaredField("name");
field.setAccessible(true);
Object fieldObject = field.get(obj);
//只对obj有效
field.set(obj, "mwytest");
如果这时候再创建一个TestClassCtor对象,它的name属性值为空而不是刚才设置的这个“mwytest”
TestClassCtor testClassCtor = new TestClassCtor(100);
testClassCtor.getName(); //仍然返回null,并没有修改
- 获取类的私有静态字段并修改它,比如在TestClassCtor中有一个私有静态字段
private static String address = "abc";
要修改这个值,代码如下
Class r = Class.forName("com.mwy.testreflection.TestClassCtor");
//获取address静态字段,private
Field field = r.getDeclaredField("address");
field.setAccessible(true);
Object fieldObject = field.get(null);
field.set(fieldObject, "ABCD");
//静态变量,一次修改,终生受用
TestClassCtor.printAddress();
- 泛型类的反射:比如Android源码SingleTon。经常用的startActivity,通过跟踪代码在Activity.java中最终会调用startActivityForResult,而在这个方法里面调用的是Instrumentation中的execStartActivity,而在execStartActivity中调用的是ActivityManagerNative.getDefault().startActivity。这里的getDefault其实是调用了sDefault.get()方法
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
}
这里的SIngleton源码为
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;
}
}
}
接下来就看看如何hook这个
//获取AMN的gDefault单例gDefault,gDefault是静态的
Object gDefault = RefInvoke.getStaticFieldObject("android.app.ActivityManagerNative", "gDefault");
// gDefault是一个 android.util.Singleton对象; 我们取出这个单例里面的mInstance字段,IActivityManager类型
Object rawIActivityManager = RefInvoke.getFieldObject(
"android.util.Singleton",
gDefault, "mInstance");
// 创建一个这个对象的代理对象iActivityManagerInterface, 然后替换这个字段, 让我们的代理对象帮忙干活
Class<?> iActivityManagerInterface = Class.forName("android.app.IActivityManager");
Object proxy = Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class<?>[] { iActivityManagerInterface },
new HookHandler(rawIActivityManager));
//把Singleton的mInstance替换为proxy
RefInvoke.setFieldObject("android.util.Singleton", gDefault, "mInstance", proxy);
然后在Activity中替换这个
public class MainActivity extends AppCompatActivity {
// 这个方法比onCreate调用早; 在这里Hook比较好.
@Override
protected void attachBaseContext(Context newBase) {
HookHelper.hookActivityManager();
super.attachBaseContext(newBase);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button tv = new Button(this);
tv.setText("测试界面");
setContentView(tv);
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 测试AMS HOOK (调用其相关方法)
Uri uri = Uri.parse("http://wwww.baidu.com");
Intent t = new Intent(Intent.ACTION_VIEW);
t.setData(uri);
startActivity(t);
}
}); }
}
跳转后log

可以看到hook成功了
这里的RefInvoke是对反射先关方法的封装
public class RefInvoke {
//无参
public static Object createObject(String className) {
Class[] pareTyples = new Class[]{};
Object[] pareVaules = new Object[]{};
try {
Class r = Class.forName(className);
return createObject(r, pareTyples, pareVaules);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
//无参
public static Object createObject(Class clazz) {
Class[] pareTyple = new Class[]{};
Object[] pareVaules = new Object[]{};
return createObject(clazz, pareTyple, pareVaules);
}
//一个参数
public static Object createObject(String className, Class pareTyple, Object pareVaule) {
Class[] pareTyples = new Class[]{ pareTyple };
Object[] pareVaules = new Object[]{ pareVaule };
try {
Class r = Class.forName(className);
return createObject(r, pareTyples, pareVaules);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
//一个参数
public static Object createObject(Class clazz, Class pareTyple, Object pareVaule) {
Class[] pareTyples = new Class[]{ pareTyple };
Object[] pareVaules = new Object[]{ pareVaule };
return createObject(clazz, pareTyples, pareVaules);
}
//多个参数
public static Object createObject(String className, Class[] pareTyples, Object[] pareVaules) {
try {
Class r = Class.forName(className);
return createObject(r, pareTyples, pareVaules);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
//多个参数
public static Object createObject(Class clazz, Class[] pareTyples, Object[] pareVaules) {
try {
Constructor ctor = clazz.getDeclaredConstructor(pareTyples);
ctor.setAccessible(true);
return ctor.newInstance(pareVaules);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//多个参数
public static Object invokeInstanceMethod(Object obj, String methodName, Class[] pareTyples, Object[] pareVaules) {
if (obj == null)
return null;
try {
//调用一个private方法
Method method = obj.getClass().getDeclaredMethod(methodName, pareTyples); //在指定类中获取指定的方法
method.setAccessible(true);
return method.invoke(obj, pareVaules);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//一个参数
public static Object invokeInstanceMethod(Object obj, String methodName, Class pareTyple, Object pareVaule) {
Class[] pareTyples = {pareTyple};
Object[] pareVaules = {pareVaule};
return invokeInstanceMethod(obj, methodName, pareTyples, pareVaules);
}
//无参
public static Object invokeInstanceMethod(Object obj, String methodName) {
Class[] pareTyples = new Class[]{};
Object[] pareVaules = new Object[]{};
return invokeInstanceMethod(obj, methodName, pareTyples, pareVaules);
}
//无参
public static Object invokeStaticMethod(String className, String method_name) {
Class[] pareTyples = new Class[]{};
Object[] pareVaules = new Object[]{};
return invokeStaticMethod(className, method_name, pareTyples, pareVaules);
}
//一个参数
public static Object invokeStaticMethod(String className, String method_name, Class pareTyple, Object pareVaule) {
Class[] pareTyples = new Class[]{pareTyple};
Object[] pareVaules = new Object[]{pareVaule};
return invokeStaticMethod(className, method_name, pareTyples, pareVaules);
}
//多个参数
public static Object invokeStaticMethod(String className, String method_name, Class[] pareTyples, Object[] pareVaules) {
try {
Class obj_class = Class.forName(className);
return invokeStaticMethod(obj_class, method_name, pareTyples, pareVaules);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//无参
public static Object invokeStaticMethod(Class clazz, String method_name) {
Class[] pareTyples = new Class[]{};
Object[] pareVaules = new Object[]{};
return invokeStaticMethod(clazz, method_name, pareTyples, pareVaules);
}
//一个参数
public static Object invokeStaticMethod(Class clazz, String method_name, Class classType, Object pareVaule) {
Class[] classTypes = new Class[]{classType};
Object[] pareVaules = new Object[]{pareVaule};
return invokeStaticMethod(clazz, method_name, classTypes, pareVaules);
}
//多个参数
public static Object invokeStaticMethod(Class clazz, String method_name, Class[] pareTyples, Object[] pareVaules) {
try {
Method method = clazz.getDeclaredMethod(method_name, pareTyples);
method.setAccessible(true);
return method.invoke(null, pareVaules);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//简写版本
public static Object getFieldObject(Object obj, String filedName) {
return getFieldObject(obj.getClass(), obj, filedName);
}
public static Object getFieldObject(String className, Object obj, String filedName) {
try {
Class obj_class = Class.forName(className);
return getFieldObject(obj_class, obj, filedName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
public static Object getFieldObject(Class clazz, Object obj, String filedName) {
try {
Field field = clazz.getDeclaredField(filedName);
field.setAccessible(true);
return field.get(obj);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//简写版本
public static void setFieldObject(Object obj, String filedName, Object filedVaule) {
setFieldObject(obj.getClass(), obj, filedName, filedVaule);
}
public static void setFieldObject(Class clazz, Object obj, String filedName, Object filedVaule) {
try {
Field field = clazz.getDeclaredField(filedName);
field.setAccessible(true);
field.set(obj, filedVaule);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void setFieldObject(String className, Object obj, String filedName, Object filedVaule) {
try {
Class obj_class = Class.forName(className);
setFieldObject(obj_class, obj, filedName, filedVaule);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Object getStaticFieldObject(String className, String filedName) {
return getFieldObject(className, null, filedName);
}
public static Object getStaticFieldObject(Class clazz, String filedName) {
return getFieldObject(clazz, null, filedName);
}
public static void setStaticFieldObject(String classname, String filedName, Object filedVaule) {
setFieldObject(classname, null, filedName, filedVaule);
}
public static void setStaticFieldObject(Class clazz, String filedName, Object filedVaule) {
setFieldObject(clazz, null, filedName, filedVaule);
}
}