Android反射相關(guān)知識匯總
一、什么是反射機制?
JAVA反射機制是在運行狀態(tài)中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調(diào)用它的任意方法和屬性;這種動態(tài)獲取信息以及動態(tài)調(diào)用對象方法的功能稱為Java語言的反射機制。
官方文檔上介紹:反射技術(shù)通常被用來檢測和改變應(yīng)用程序在Java虛擬機中的行為表現(xiàn)。它是一個相對而言比較高級的技術(shù),通常它應(yīng)用的前提是開發(fā)者本身對于Java語言特性有很強的理解的基礎(chǔ)上。反射是一種強有力的技術(shù)特性,因此可以使得應(yīng)用程序突破一些無法企及的目的。
二、我們需要知道哪些理論基礎(chǔ)?
-
Class:Class對象是一個特殊的對象,是用來創(chuàng)建其它Java的實例,Class對象就是Java類編譯后生成的.class文件,它包含了與類有關(guān)的信息。
-
Field:Filed字段提供有關(guān)和動態(tài)訪問的信息,類或接口的單個字段。反射的字段可能是類字段或?qū)嵗侄巍?/h4>
-
Method:Method方法提供了關(guān)于單個方法的信息和訪問在類或接口上。反射的方法可能是類方法或者是一個實例方法(包括一個抽象的方法)。
-
Constructor:Constructor提供了關(guān)于某類的構(gòu)造方法的所需信息。
三、我們需要掌握哪些方法呢?
1、類名.class; 不執(zhí)行靜態(tài)塊和動態(tài)構(gòu)造塊。
2、Class.forName(path); 執(zhí)行靜態(tài)塊,不執(zhí)行動態(tài)構(gòu)造塊。
3、對象.getClass(); 需要創(chuàng)建對象,靜態(tài)塊和動態(tài)構(gòu)造塊均會執(zhí)行。
1、class.getField(fieldName); 只能獲取public修飾的字段
2、class.getFields(); 獲取所有public修飾的字段的Field數(shù)組
3、class.getDeclaredField(fieldName); 可以獲得所有字段
4、class.getDeclaredFields(); 獲取所有字段的Field數(shù)組
1、class.getMethod(methodName); 只能獲取public修飾的方法名稱
2、class.getMethods(); 獲取所有public修飾的方法的Method數(shù)組
3、class.getDeclaredMethod(methodName); 可以獲得所有方法
4、class.getDeclaredMethods(); 獲取所有方法的Method數(shù)組
-
獲取構(gòu)造函數(shù)Constructor的幾個方法:
1、class.getConstructor(methodName); 只能獲取public修飾的方法名稱
2、class.getConstructors(); 獲取所有public修飾的方法的Method數(shù)組
3、class.getDeclaredConstructor(methodName); 可以獲得所有方法
4、class.getDeclaredConstructors(); 獲取所有方法的Method數(shù)組
1、Constructor.newInstance(可變參數(shù));
eg:Persion p = (Persion)constructor.newInstance("1");
(1) field.set(Objkect obj,Object value);
(2) field.setInt(Objkect obj,int value);
...
(n) file.setLong(Objkect obj,long value);
(1) field.get(Object);
eg:Person p = (Persion)filed.get(對象);
這里必須注意的是當(dāng)操作的對象用private修飾的時候需要用method.setAccessible(true)來設(shè)置可以訪問到.
然后調(diào)用method.invoke(Object obj,參數(shù)),這個Object的對象必須是該類的對象.不是所謂的類對象.
四.Android能用到的地方
-
修改TabLayout的下劃線的長度.對于TabLayout的使用這里就不必多說了,系統(tǒng)只提供了修改下劃線的高度和顏色的方法,并沒有修改長度的方法.這里就要用到反射區(qū)獲取TabLayout內(nèi)部控制長度的方法.這里只能通過設(shè)置每個Tab的Margin來控制下劃線的寬度,有可能出現(xiàn)Tab的文字被擠壓的情況,只能將就使用了.代碼如下:
Class<? extends TabLayout> tabClass = tabLayout.getClass();
try {
Field mTabStrip = tabClass.getDeclaredField("mTabStrip");
mTabStrip.setAccessible(true);
LinearLayout linearLayout = (LinearLayout) mTabStrip.get(tabLayout);
for (int i = 0; i < linearLayout.getChildCount(); i++) {
View child = linearLayout.getChildAt(i);
child.setPadding(0,0,0,0);
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) child.getLayoutParams();
// layoutParams.width = 300;
layoutParams.leftMargin = 150;
layoutParams.rightMargin = 150;
child.setLayoutParams(layoutParams);
child.invalidate();
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
-
控制Toast的顯示時間.Toast內(nèi)部類TN的設(shè)置顯示時間的代碼:
這里系統(tǒng)自帶的Toast只給了我們兩個時間的選擇SHORT_DURATION_TIMEOUT和LONG_DURATION_TIMEOUT其他的我們沒法改變.還好系統(tǒng)提供了hide方法不過在外面我們是訪問不到,這里我們也可以用到反射,大部分的操作都是Toast的內(nèi)部類TN來完成的.首先獲取到Toast的class對象,Toast內(nèi)部含有內(nèi)部類的字段(final TN mTN),這樣我們可以獲取到內(nèi)部類的對象,然后再通過內(nèi)部類的Class對象來獲取內(nèi)部類里面的hide()方法.代碼如下:
mParams.hideTimeoutMilliseconds = mDuration ==
Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT;
...
/**
* schedule handleHide into the right thread
*/
@Override
public void hide() {
if (localLOGV) Log.v(TAG, "HIDE: " + this);
mHandler.obtainMessage(HIDE).sendToTarget();
}
try{
Class<Toast> toastClass = Toast.class;
Field mTN = toastClass.getDeclaredField("mTN");
//獲取修飾符類型
toastClass.getModifiers();
mTN.setAccessible(true);
Object o = mTN.get(toast);
Class<?> aClass = o.getClass();
Method hide = aClass.getDeclaredMethod("hide");
hide.setAccessible(true);
hide.invoke(o);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}