Android反射相關(guān)知識(shí)匯總
一睦擂、什么是反射機(jī)制?
JAVA反射機(jī)制是在運(yùn)行狀態(tài)中选浑,對于任意一個(gè)類蓝厌,都能夠知道這個(gè)類的所有屬性和方法;對于任意一個(gè)對象古徒,都能夠調(diào)用它的任意方法和屬性拓提;這種動(dòng)態(tài)獲取信息以及動(dòng)態(tài)調(diào)用對象方法的功能稱為Java語言的反射機(jī)制。
官方文檔上介紹:反射技術(shù)通常被用來檢測和改變應(yīng)用程序在Java虛擬機(jī)中的行為表現(xiàn)隧膘。它是一個(gè)相對而言比較高級的技術(shù)代态,通常它應(yīng)用的前提是開發(fā)者本身對于Java語言特性有很強(qiáng)的理解的基礎(chǔ)上寺惫。反射是一種強(qiáng)有力的技術(shù)特性,因此可以使得應(yīng)用程序突破一些無法企及的目的蹦疑。
二西雀、我們需要知道哪些理論基礎(chǔ)?
-
Class:Class對象是一個(gè)特殊的對象歉摧,是用來創(chuàng)建其它Java的實(shí)例艇肴,Class對象就是Java類編譯后生成的.class文件,它包含了與類有關(guān)的信息叁温。
-
Field:Filed字段提供有關(guān)和動(dòng)態(tài)訪問的信息再悼,類或接口的單個(gè)字段。反射的字段可能是類字段或?qū)嵗侄巍?/h4>
-
Method:Method方法提供了關(guān)于單個(gè)方法的信息和訪問在類或接口上膝但。反射的方法可能是類方法或者是一個(gè)實(shí)例方法(包括一個(gè)抽象的方法)冲九。
-
Constructor:Constructor提供了關(guān)于某類的構(gòu)造方法的所需信息。
三跟束、我們需要掌握哪些方法呢莺奸?
1、類名.class; 不執(zhí)行靜態(tài)塊和動(dòng)態(tài)構(gòu)造塊泳炉。
2憾筏、Class.forName(path); 執(zhí)行靜態(tài)塊,不執(zhí)行動(dòng)態(tài)構(gòu)造塊花鹅。
3氧腰、對象.getClass(); 需要?jiǎng)?chuàng)建對象,靜態(tài)塊和動(dòng)態(tài)構(gòu)造塊均會(huì)執(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的幾個(gè)方法:
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修飾的時(shí)候需要用method.setAccessible(true)來設(shè)置可以訪問到.
然后調(diào)用method.invoke(Object obj,參數(shù)),這個(gè)Object的對象必須是該類的對象.不是所謂的類對象.
四.Android能用到的地方
-
修改TabLayout的下劃線的長度.對于TabLayout的使用這里就不必多說了,系統(tǒng)只提供了修改下劃線的高度和顏色的方法,并沒有修改長度的方法.這里就要用到反射區(qū)獲取TabLayout內(nèi)部控制長度的方法.這里只能通過設(shè)置每個(gè)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的顯示時(shí)間.Toast內(nèi)部類TN的設(shè)置顯示時(shí)間的代碼:
這里系統(tǒng)自帶的Toast只給了我們兩個(gè)時(shí)間的選擇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();
}