在計算機科學領域,反射是指一類應用,它們能夠自描述和自控制。也就是說,這類應用通過采用某種機制來實現對自己行為的描述(self-representation)和監測(examination),并能根據自身行為的狀態和結果,調整或修改應用所描述行為的狀態和相關的語義.反射 是 Java 程序開發語言的特征之一,它允許運行中的 Java 程序對自身進行檢查,或者說“自審”,并能直接操作程序的內部屬性。Java 的反射機制的實現要借助于4個類:class,Constructor,Field,Method;其中class代表的時類對 象,Constructor-類的構造器對象,Field-類的屬性對象,Method-類的方法對象。
**1.通過反射技術可以訪問到其他包名下數據方法等,這些為一些APK換皮膚提供了方便**
首先初始化skinContext
~~~
try {
skinContext = this.createPackageContext("com.skin",
CONTEXT_IGNORE_SECURITY|CONTEXT_INCLUDE_CODE);
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
skinContext=null;
e.printStackTrace();
}
~~~
可以通過下面的方法訪問到指定包名下的資源ID
~~~
/**
* 取得對應包的所有資源的ID
* 存在MAP中
* @param packageName
* @return
*/
private Map<String,Map<String, Object>> getSkinResourcesId(String packageName)
{
Map<String, Object> temp = null;
Map<String,Map<String, Object>> resMap =new HashMap<String,Map<String,Object>>();
try {
//取得皮膚包中的R文件
Class<?> rClass = skinContext.getClassLoader().loadClass(packageName+".R");
//取得記錄各種資源的ID的類
Class<?>[] resClass =rClass.getClasses();
String className,resourceName;
int resourceId=0;
for(int i=0;i<resClass.length;i++)
{
className = resClass[i].getName();
//取得該類的資源
Field field[] = resClass[i].getFields();
for(int j =0;j < field.length; j++)
{
resourceName = field[j].getName();
try {
resourceId = field[j].getInt(resourceName);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(resourceName!=null && !resourceName.equals(""))
{
temp =new HashMap<String, Object>();
temp.put(resourceName, resourceId);
Log.i("DDDDD", "className:"+className+" resourceName:"+resourceName+" " +
"resourceId:"+Integer.toHexString(resourceId));
}
}
//由于內部類的關系className應該是com.skin.R$layout的形式
//截掉前面的包名和.R$以方便使用
className = className.substring(packageName.length()+3);
resMap.put(className, temp);
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return resMap;
}
~~~
最后通過資源ID和skinContext可以訪問到指定包下的所有資源,例如要訪問layout
~~~
/**
* 獲取皮膚包中的layout
* 并轉化為VIEW
* @param layoutName
* @return
*/
private View getLayoutFromSkin(String layoutName)
{
View view;
if(resMap == null)
return null;
Map<String, Object> temp = resMap.get("layout");
int viewId = (Integer) temp.get(layoutName);
if(viewId != 0)
{
//引用皮膚包資源轉化View
LayoutInflater inflater =LayoutInflater.from(skinContext);
view = inflater.inflate(skinContext.getResources().getLayout(viewId), null);
}
else
{
view = null;
}
return view;
}
~~~
注:換皮膚思路詳見:[http://blog.csdn.net/tangnengwu/article/details/22801107](http://blog.csdn.net/tangnengwu/article/details/22801107)
**2. 訪問android 隱藏的API**
Toast信息框的關閉是由系統管理的,因為hide方法是隱藏的開發者沒有辦法直接調用,這種情況下可以用發射機制獲取這個方法,創建一個顯示和隱藏都由開發者控制的Toast信息框。
~~~
package com.example.reflection;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class MyToast
{
Context context=null;
Object obj =null;
public MyToast(Context context,String text)
{
this.context =context;
Toast toast =Toast.makeText(context, text, 1);
try {
Field field = toast.getClass().getDeclaredField("mTN");
field.setAccessible(true);
obj =field.get(toast);
} catch (Exception e) {
// TODO: handle exception
Log.d("AAA", "MyToast Exception--->"+e.toString());
}
}
public void show()
{
try {
//android4.0以上就要以下處理
// Field mNextViewField = obj.getClass().getDeclaredField("mNextView");
// mNextViewField.setAccessible(true);
// LayoutInflater inflate = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// View v = inflate.inflate(R.layout.ui_toast, null);
// mNextViewField.set(obj, v);
Method method =obj.getClass().getDeclaredMethod("show", null);
method.invoke(obj, null);
} catch (Exception e) {
// TODO Auto-generated catch block
Log.d("AAA", "show Exception--->"+e.toString());
e.printStackTrace();
}
}
public void hide()
{
try {
Method method =obj.getClass().getDeclaredMethod("hide", null);
method.invoke(obj, null);
} catch (Exception e) {
// TODO Auto-generated catch block
Log.d("AAA", "hide Exception--->"+e.toString());
e.printStackTrace();
}
}
}
~~~
顯示toast:
~~~
MyToast toast = new MyToast(this, "反射機制!");
toast.show();
~~~
隱藏toast:
toast.hide();
**注意在4.0以上的版本中,還需要對Toast 中的View進行處理,如代碼中所示**
**3. 修改某些“不可改” 的系統資源**
ListView組件沒有提供修改快速滑塊圖像的API,因此不能直接修改,但可通過反射實現
~~~
package com.example.reflection;
import java.lang.reflect.Field;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.AbsListView;
import android.widget.ListView;
public class MListView extends ListView
{
public MListView(Context context, AttributeSet attrs)
{
super(context, attrs);
// TODO Auto-generated constructor stub
setNewDrawable(context);
}
private void setNewDrawable(Context context)
{
try {
Field field = AbsListView.class.getDeclaredField("mFastScroller");
field.setAccessible(true);
Object obj = field.get(this);
field =field.getType().getDeclaredField("mThumbDrawable");
field.setAccessible(true);
Drawable drawable = (Drawable)field.get(obj);
drawable = context.getResources().getDrawable(R.drawable.ic_launcher);
field.set(obj, drawable);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
~~~
~~~
Field field = AbsListView.class.getDeclaredField("mFastScroller");
~~~
FastScroller.mThunbDrawable變量保存了快速滑塊圖像,但首先要獲取AbsListView.mFastScroller變量
~~~
<com.example.reflection.MListView
android:id="@+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fastScrollEnabled="true"
android:scrollbars="none"
>
</com.example.reflection.MListView>
~~~
~~~
android:fastScrollEnabled="true"
~~~
使用快速滑塊
效果圖如下:

總結:
???? Java中的反射機制,被稱為Reflection,它允許運行中的Java程序對自身進行檢查,并能直接操作程序的內部屬性或方法。Reflection機制允許程序在正在執行的過程中,利用Reflection APIs取得任何已知名稱的類的內部信息,包括:package、 type parameters、 superclass、 implemented interfaces、 inner classes、 outer classes、 fields、 constructors、 methods、 modifiers等,并可以在執行的過程中,動態生成Instances、變更fields內容或喚起methods。再次基礎上我們可以利用反射機制在Java程序中,動態的去調用一些protected甚至是private的方法或類,這樣可以很大程度上滿足我們的一些比較特殊需求。
有關反射技術的API:
Class類:
Class類代表著某個類的字節碼,要使用反射,就需要取得對應的Class對象,然后就通過這個對象,就可解剖出類的成員變量,成員方法等等。
獲取Class類對象
//通過Class的forName()方法,此方法最為常用 ?
Class class1 = Class.forName(className); ?
//通過 .class ?
Class class2 = XXX.class; ?
//通過對象獲得 ?
Class class3 = new XXX().getClass();?
Class類的常用方法:
getConstructor() 獲取構造函數
getMethod() ?獲取成員方法
getField() 獲取成員變量
getDeclaredConstructor() 獲取私有的構造函數
getDeclaredMethod() ?獲取私有的成員方法
getDeclaredField() 獲取私有的成員變量
取得method對象之后
調用
~~~
method.invoke(obj, null)
~~~
使用該方法