一戳寸、反射的概述
JAVA
反射機(jī)制是在運(yùn)行狀態(tài)
中,對(duì)于任意一個(gè)類
郑诺,都能夠知道這個(gè)類
的所有 屬性和方法
;對(duì)于任意一個(gè)對(duì)象
杉武,都能夠調(diào)用
它的任意一個(gè)方法和屬性
辙诞;這種動(dòng)態(tài)
獲取的信息以及動(dòng)態(tài)調(diào)用對(duì)象的方法的功能稱為java
語言的反射機(jī)制。
Java
程序可以加載一個(gè)運(yùn)行時(shí)才得知名稱的class
艺智,獲悉其完整構(gòu)造(但不包括methods
定義)倘要,并生成其對(duì)象實(shí)體、或?qū)ζ?code>fields設(shè)值、或喚起其methods
封拧。
要想解剖一個(gè)類,必須先要獲取到該類 的字節(jié)碼文件對(duì)象
志鹃。而解剖使用的就是Class
類中的方法.所以先要獲取到每一個(gè)字節(jié)碼文件
對(duì)應(yīng)的Class類型的對(duì)象
。
使用的前提條件:必須先得到代表的字節(jié)碼的Class
泽西,Class
類用于表示.class
文件(字節(jié)碼)反射是框架設(shè)計(jì)的靈魂曹铃,以上的總結(jié)就是什么是反射
反射就是把java
類中的各種成分映射成一個(gè)個(gè)的Java對(duì)象
例如:一個(gè)類有:成員變量、方法捧杉、構(gòu)造方法陕见、包等等信息,利用反射技術(shù)可以對(duì)一個(gè)類進(jìn)行解剖味抖,把個(gè)個(gè)組成部分映射成一個(gè)個(gè)對(duì)象评甜。
(其實(shí):一個(gè)類中這些成員方法、構(gòu)造方法仔涩、在加入類中都有一個(gè)類來描述)
如圖是類的正常加載過程:反射的原理在于class對(duì)象
忍坷。
加載的時(shí)候:Class對(duì)象
的由來是將class文件
讀入內(nèi)存
,并為之創(chuàng)建一個(gè)Class對(duì)象
熔脂。
在運(yùn)行期間佩研,如果我們要產(chǎn)生某個(gè)類的對(duì)象,Java
虛擬機(jī)(JVM)
會(huì)檢查該類型的Class
對(duì)象是否已被加載霞揉。如果沒有被加載旬薯,JVM
會(huì)根據(jù)類的名稱找到.class
文件并加載它。一旦某個(gè)類型的Class
對(duì)象已被加載到內(nèi)存适秩,就可以用它來產(chǎn)生該類型的所有對(duì)象绊序。
反射機(jī)制主要提供的功能
- 在運(yùn)行時(shí)判斷任意一個(gè)對(duì)象所屬的類;
- 在運(yùn)行時(shí)構(gòu)造任意一個(gè)類的對(duì)象秽荞;
- 在運(yùn)行時(shí)判斷任意一個(gè)類所具有的成員變量和方法政模;
- 在運(yùn)行時(shí)調(diào)用任意一個(gè)對(duì)象的方法;
Java中創(chuàng)建對(duì)象大概有這幾種方式:
1蚂会、使用new關(guān)鍵字:這是我們最常見的也是最簡(jiǎn)單的創(chuàng)建對(duì)象的方式
2、使用Clone的方法:無論何時(shí)我們調(diào)用一個(gè)對(duì)象的clone方法耗式,JVM就會(huì)創(chuàng)建一個(gè)新的對(duì)象胁住,將前面的對(duì)象的內(nèi)容全部拷貝進(jìn)去
3、使用反序列化:當(dāng)我們序列化和反序列化一個(gè)對(duì)象刊咳,JVM會(huì)給我們創(chuàng)建一個(gè)單獨(dú)的對(duì)象
4彪见、反射
獲取類的字節(jié)碼:
(1)、Class.forName("com.test.User");
(2)娱挨、對(duì)象.getClass();
(3)余指、類名.class;
java中的Class中一些重要的方法
-
public Annotation[] getAnnotations ()
獲取這個(gè)類中所有注解 -
getClassLoader()
獲取加載這個(gè)類的類加載器 -
getDeclaredMethods()
獲取這個(gè)類中的所有方法 -
getReturnType()
獲取方法的返回類型 -
getParameterTypes()
獲取方法的傳入?yún)?shù)類型* -
isAnnotation()
測(cè)試這類是否是一個(gè)注解類 -
getDeclaredConstructors()
獲取所有的構(gòu)造方法 -
getDeclaredMethod(String name, Class… parameterTypes)
獲取指定的構(gòu)造方法(參數(shù):參數(shù)類型.class
) -
getSuperclass()
獲取這個(gè)類的父類 -
getInterfaces()
獲取這個(gè)類實(shí)現(xiàn)的所有接口 -
getFields()
獲取這個(gè)類中所有被public
修飾的成員變量 -
getField(String name)
獲取指定名字的被public
修飾的成員變量 -
newInstance()
返回此Class
所表示的類,通過調(diào)用默認(rèn)的(即無參數(shù))構(gòu)造函數(shù)創(chuàng)建的一個(gè)新實(shí)例
注意:
在反射私有的構(gòu)造函數(shù)時(shí),用普通的clazz.getConstructor()
會(huì)報(bào)錯(cuò)酵镜,因?yàn)樗撬接械牡锏铮蕴峁┝藢iT反射私有構(gòu)造函數(shù)的方法。
//讀取私有的構(gòu)造函數(shù)淮韭,用這個(gè)方法讀取完還需要設(shè)置一下暴力反射才可以
-
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;
}
}
實(shí)例化反射對(duì)象 構(gòu)造方法
constructor.setAccessible(true)
是獲取到反射的權(quán)限
垢粮,如果構(gòu)造方法為私有
的則需要設(shè)置為true
, 參數(shù)值為true
靠粪,打開禁用訪問控制檢查蜡吧,setAccessible(true)
并不是將方法的訪問權(quán)限改成了public
,而是取消java
的權(quán)限控制檢查占键。所以即使是public
方法昔善,其accessible
屬相默認(rèn)也是false
/***
* 采用默認(rèn)構(gòu)造方法實(shí)例化對(duì)象
* com.test.User想反射類的全路徑
*/
Class mClass = Class.forName("com.test.User");
//得到User類的構(gòu)造方法,可以創(chuàng)建對(duì)象
Constructor constructor = mClass.getConstructor();
Object mStu = constructor.newInstance();
/***
* 采用參數(shù)構(gòu)造
*/
Class mClass2 = Class.forName("com.test.User");
Constructor constructor2 = mClass2.getConstructor( int.class,String.class);
constructor2.setAccessible(true);
Object object2 = constructor2.newInstance(10,"xx1");
/***
* 調(diào)用private的有參構(gòu)造方法
*/
Class mClass3 = Class.forName("com.test.User");
Constructor constructor3 = mClass3.getDeclaredConstructor(String.class);
//獲取到反射的權(quán)限畔乙,如果構(gòu)造方法為私有的則需要設(shè)置為true君仆。
constructor3.setAccessible(true);
Object object3 = constructor3.newInstance("xx2");
反射調(diào)用方法
/***
* 調(diào)用無參的方法
*/
Method nameMethod = mClass.getDeclaredMethod("getName");
nameMethod.setAccessible(true);
nameMethod.invoke(object1);
/***
* 反射調(diào)用setName方法
*/
Method getNameMethod = mClass.getDeclaredMethod("setName", String.class);
getNameMethod.invoke(object3, "一個(gè)參數(shù)");
/***
* 反射調(diào)用setIdName
*/
Method setNameAndAgeMethod = mClass.getDeclaredMethod("setIdName", int.class, String.class);
setNameAndAgeMethod.setAccessible(true);
setNameAndAgeMethod.invoke(object2, 8, "2個(gè)參數(shù)");
反射設(shè)置屬性的值
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;
}
/***
* 遞歸調(diào)用
* @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反射機(jī)制操作成員變量, 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住點(diǎn)擊事件了,禽獸", Toast.LENGTH_SHORT).show();
if (onClickListener != null) {
onClickListener.onClick(v);
}
}
}
}
Java基礎(chǔ)之—反射(非常重要)
夯實(shí)JAVA基本之二 —— 反射(1):基本類周邊信息獲取
Java中的反射機(jī)制介紹
android的hook技術(shù)之hook所有view的監(jiān)聽
學(xué)習(xí)java應(yīng)該如何理解反射啸澡?
java反射之Method的invoke方法實(shí)現(xiàn)
Android反射機(jī)制:手把手教你實(shí)現(xiàn)反射
Android反射