一、反射的概述
JAVA
反射机制是在运行状态
中,对于任意一个类
,都能够知道这个类
的所有 属性和方法
;对于任意一个对象
,都能够调用
它的任意一个方法和属性
;这种动态
获取的信息以及动态调用对象的方法的功能称为java
语言的反射机制。
Java
程序可以加载一个运行时才得知名称的class
,获悉其完整构造(但不包括methods
定义),并生成其对象实体、或对其fields
设值、或唤起其methods
。
要想解剖一个类,必须先要获取到该类 的字节码文件对象
。而解剖使用的就是Class
类中的方法.所以先要获取到每一个字节码文件
对应的Class类型的对象
。
使用的前提条件:必须先得到代表的字节码的Class
,Class
类用于表示.class
文件(字节码)反射是框架设计的灵魂,以上的总结就是什么是反射
反射就是把java
类中的各种成分映射成一个个的Java对象
例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。
(其实:一个类中这些成员方法、构造方法、在加入类中都有一个类来描述)
如图是类的正常加载过程:反射的原理在于class对象
。
加载的时候:Class对象
的由来是将class文件
读入内存
,并为之创建一个Class对象
。
在运行期间,如果我们要产生某个类的对象,Java
虚拟机(JVM)
会检查该类型的Class
对象是否已被加载。如果没有被加载,JVM
会根据类的名称找到.class
文件并加载它。一旦某个类型的Class
对象已被加载到内存,就可以用它来产生该类型的所有对象。
反射机制主要提供的功能
- 在运行时判断任意一个对象所属的类;
- 在运行时构造任意一个类的对象;
- 在运行时判断任意一个类所具有的成员变量和方法;
- 在运行时调用任意一个对象的方法;
Java中创建对象大概有这几种方式:
1、使用new关键字:这是我们最常见的也是最简单的创建对象的方式
2、使用Clone的方法:无论何时我们调用一个对象的clone方法,JVM就会创建一个新的对象,将前面的对象的内容全部拷贝进去
3、使用反序列化:当我们序列化和反序列化一个对象,JVM会给我们创建一个单独的对象
4、反射
获取类的字节码:
(1)、Class.forName("com.test.User");
(2)、对象.getClass();
(3)、类名.class;
java中的Class中一些重要的方法
-
public Annotation[] getAnnotations ()
获取这个类中所有注解 -
getClassLoader()
获取加载这个类的类加载器 -
getDeclaredMethods()
获取这个类中的所有方法 -
getReturnType()
获取方法的返回类型 -
getParameterTypes()
获取方法的传入参数类型* -
isAnnotation()
测试这类是否是一个注解类 -
getDeclaredConstructors()
获取所有的构造方法 -
getDeclaredMethod(String name, Class… parameterTypes)
获取指定的构造方法(参数:参数类型.class
) -
getSuperclass()
获取这个类的父类 -
getInterfaces()
获取这个类实现的所有接口 -
getFields()
获取这个类中所有被public
修饰的成员变量 -
getField(String name)
获取指定名字的被public
修饰的成员变量 -
newInstance()
返回此Class
所表示的类,通过调用默认的(即无参数)构造函数创建的一个新实例
注意:
在反射私有的构造函数时,用普通的clazz.getConstructor()
会报错,因为它是私有的,所以提供了专门反射私有构造函数的方法。
//读取私有的构造函数,用这个方法读取完还需要设置一下暴力反射才可以
-
clazz.getDeclaredConstructor(int.class);
//暴力反射 -
c.setAccessible(true)
;
User类
package com.test;
public class User {
private int id;
private String name;
private String age;
public User() {
}
public User(int id) {
this.id = id;
}
private User(String name) {
this.name = name;
}
public User(int id, String name) {
this.id = id;
this.name = name;
}
public User(String name, String age) {
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private void setIdName(int id, String name) {
this.id = id;
this.name = name;
}
}
实例化反射对象 构造方法
constructor.setAccessible(true)
是获取到反射的权限
,如果构造方法为私有
的则需要设置为true
, 参数值为true
,打开禁用访问控制检查,setAccessible(true)
并不是将方法的访问权限改成了public
,而是取消java
的权限控制检查。所以即使是public
方法,其accessible
属相默认也是false
/***
* 采用默认构造方法实例化对象
* com.test.User想反射类的全路径
*/
Class mClass = Class.forName("com.test.User");
//得到User类的构造方法,可以创建对象
Constructor constructor = mClass.getConstructor();
Object mStu = constructor.newInstance();
/***
* 采用参数构造
*/
Class mClass2 = Class.forName("com.test.User");
Constructor constructor2 = mClass2.getConstructor( int.class,String.class);
constructor2.setAccessible(true);
Object object2 = constructor2.newInstance(10,"xx1");
/***
* 调用private的有参构造方法
*/
Class mClass3 = Class.forName("com.test.User");
Constructor constructor3 = mClass3.getDeclaredConstructor(String.class);
//获取到反射的权限,如果构造方法为私有的则需要设置为true。
constructor3.setAccessible(true);
Object object3 = constructor3.newInstance("xx2");
反射调用方法
/***
* 调用无参的方法
*/
Method nameMethod = mClass.getDeclaredMethod("getName");
nameMethod.setAccessible(true);
nameMethod.invoke(object1);
/***
* 反射调用setName方法
*/
Method getNameMethod = mClass.getDeclaredMethod("setName", String.class);
getNameMethod.invoke(object3, "一个参数");
/***
* 反射调用setIdName
*/
Method setNameAndAgeMethod = mClass.getDeclaredMethod("setIdName", int.class, String.class);
setNameAndAgeMethod.setAccessible(true);
setNameAndAgeMethod.invoke(object2, 8, "2个参数");
反射设置属性的值
Field nameField = mClass.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(object3, "xxxx");
Hook
package com.cc.reflection;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class HookClickListenerUtils {
private static HookClickListenerUtils mHookClickListenerUtils;
private HookClickListenerUtils() {
}
public static HookClickListenerUtils getInstance() {
synchronized ("getInstance") {
if (mHookClickListenerUtils == null) {
mHookClickListenerUtils = new HookClickListenerUtils();
}
}
return mHookClickListenerUtils;
}
/***
* 递归调用
* @param decorView
*/
public void hookDecorViewClick(View decorView) {
if (decorView instanceof ViewGroup) {
int count = ((ViewGroup) decorView).getChildCount();
for (int i = 0; i < count; i++) {
if (((ViewGroup) decorView).getChildAt(i) instanceof ViewGroup) {
hookDecorViewClick(((ViewGroup) decorView).getChildAt(i));
} else {
hookViewClick(((ViewGroup) decorView).getChildAt(i));
}
}
} else {
hookViewClick(decorView);
}
}
public void hookViewClick(View view) {
try {
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
Class viewClass = Class.forName("android.view.View");
Method getListenerInfoMethod = viewClass.getDeclaredMethod("getListenerInfo");
if (!getListenerInfoMethod.isAccessible()) {
getListenerInfoMethod.setAccessible(true);
}
// 反射view中的getListenerInfo方法
Object listenerInfoObject = getListenerInfoMethod.invoke(view);
// 第二步:获取到view中的ListenerInfo中的mOnClickListener属性
Class mListenerInfoClass = Class.forName("android.view.View$ListenerInfo");
Field mOnClickListenerField = mListenerInfoClass.getDeclaredField("mOnClickListener");
mOnClickListenerField.setAccessible(true);
// 通过Java反射机制操作成员变量, set 和 get,View.OnClickListener为Field.get()的值
mOnClickListenerField.set(listenerInfoObject, new HookClickListener((View.OnClickListener) mOnClickListenerField.get(listenerInfoObject)));
} catch (Exception e) {
e.printStackTrace();
}
}
public static class HookClickListener implements View.OnClickListener {
private View.OnClickListener onClickListener;
public HookClickListener(View.OnClickListener onClickListener) {
this.onClickListener = onClickListener;
}
@Override
public void onClick(View v) {
Toast.makeText(v.getContext(), "hook住点击事件了,禽兽", Toast.LENGTH_SHORT).show();
if (onClickListener != null) {
onClickListener.onClick(v);
}
}
}
}
Java基础之—反射(非常重要)
夯实JAVA基本之二 —— 反射(1):基本类周边信息获取
Java中的反射机制介绍
android的hook技术之hook所有view的监听
学习java应该如何理解反射?
java反射之Method的invoke方法实现
Android反射机制:手把手教你实现反射
Android反射