定義:
Reflection是java開發語言特性之一,它容許運行中的java程序對自身進行檢測,自審,並能操做程序內部的屬性和方法,Reflection是java被視爲動態語言關鍵之一。容許程序從執行期的Reflection APIS取得任何已知名稱的class內部信息,包含packages、type parameters、superclass、implement Interfaces、inner classes、outer class、fields、methods、constructors、modifiers,並可在執行期間執行instance,更變field內容,喚醒method。 html
反射過程當中經常使用的類:
java反射所須要的類並很少,他們分別是:Class、Constructor、Object、Method、Field。
Class類:每一個class都有一個相應的Class對象。也就是說,當咱們編寫一個類,編譯完成後,在生成的.class文件中,就會產生一個Class對象,在運行期間若是咱們須要產生某個類的對象,JVM就會檢測該類型的Class對象是否已經被加載,若是沒有被加載,則虛擬機會根據類名稱找到並加載相對應的.class文件,一旦某個類型的Class對象加載到內存中,就能夠用它來產生相應的對象。
Constructor類:封裝了反射類的構造方法,提供該類單個構造方法和訪問權限信息。
Object類:每一個類都使用Object做爲超類,全部的對象都實現這個類的方法。
Method類:提供有關類或者接口單獨某個方法的信息,以及動態訪問權限,所反映的方法多是類方法或者實例方法以及抽象方法。
Field類:提供有關類或者結構單獨屬性的信息,以及動態訪問權限,所反映的屬性多是類屬性或者實例屬性。
java
項目中的實際運用:
上次在講述Android AIDL IPC通訊的時候提到過,基於AIDL實現客戶端被註冊的view經過反射以及服務端傳過來的數據達成一個交互過程。實現圖片文字的顯示過程。
linux
客戶端調用:
首先:咱們須要實現咱們要註冊的MyImageView,繼承自ImageView,主要用來圖片顯示。 android
package com.zlc.aidl.client; import android.content.Context; import android.graphics.Bitmap; import android.widget.ImageView; public class MyImageView extends ImageView{ public MyImageView(Context context) { super(context); } @Override public void setImageBitmap(Bitmap bm) { // TODO Auto-generated method stub super.setImageBitmap(bm); } }
而後:咱們須要反射的工具類ReflectionInvoke.java,用來反射調用註冊view對象裏面的方法,經過服務端傳過來的參數和對應方法名來進行反射調用。在工具類中包含一個InvokeKey的內部類,主要用來標示一個對象的某個方法,並保存到工具類集合裏面,下次調用的時候不須要再進行尋找method的過程,直接invoke反射調用就行。 json
package com.zlc.aidl.client; import java.lang.ref.WeakReference; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import android.util.Log; public class ReflectionInvoke { public static HashMap<InvokeKey, WeakReference<ReflectionInvoke>> reflections = new HashMap<ReflectionInvoke.InvokeKey, WeakReference<ReflectionInvoke>>(); private Method method; private Class<?> clazz; private Class<?> parameterClasses[]; static class InvokeKey { String className; String methodName; String[] paramsClassName; public InvokeKey(String className, String methodName, String[] paramsClassName) { this.className = className; this.methodName = methodName; this.paramsClassName = paramsClassName; } @Override public int hashCode() { // TODO Auto-generated method stub int ret = className.hashCode(); ret = methodName.hashCode() + ret * 10; for (int i = 0; i < paramsClassName.length; i++) { ret = paramsClassName[i].hashCode() + ret * 10; } return ret; } @Override public boolean equals(Object o) { if (o instanceof InvokeKey) { InvokeKey key = (InvokeKey) o; if (!key.className.equals(className) || !key.methodName.equals(methodName) || key.paramsClassName.length != paramsClassName.length) { return false; } else { for (int i = 0; i < paramsClassName.length; i++) { if (!key.paramsClassName[i].equals(paramsClassName[i])) return false; } return true; } } return false; } } Class<?> classForNameX(String name) throws Exception { if ("int".equals(name)) return int.class; else if ("char".equals(name)) return char.class; else if ("short".equals(name)) return short.class; else if ("byte".equals(name)) return byte.class; else if ("long".equals(name)) return long.class; else if ("float".equals(name)) return float.class; else if ("double".equals(name)) return double.class; else if ("boolean".equals(name)) return boolean.class; return Class.forName(name); } private ReflectionInvoke(InvokeKey key) throws Exception { clazz = Class.forName(key.className); parameterClasses = new Class[key.paramsClassName.length]; for (int i = 0; i < parameterClasses.length; i++) { parameterClasses[i] = classForNameX(key.paramsClassName[i]); } method = clazz.getMethod(key.methodName, parameterClasses); } public static ReflectionInvoke getInvoker(String className, String methodName, List<String> argsClassName) { String[] arrayarges = new String[argsClassName.size()]; argsClassName.toArray(arrayarges); return getInvoker(className, methodName, arrayarges); } public static ReflectionInvoke getInvoker(String className, String methodName, String... args) { ReflectionInvoke invoke = null; synchronized (reflections) { try { InvokeKey key = new InvokeKey(className, methodName, args); WeakReference<ReflectionInvoke> w = reflections.get(key); if (w == null ? true : (invoke = w.get()) == null) { invoke = new ReflectionInvoke(key); reflections.put(key, new WeakReference<ReflectionInvoke>(invoke)); } } catch (Exception e) { e.printStackTrace(); } } return invoke; } public Object invokeNoException(Object obj, Object... args) { try { return method.invoke(obj, args); } catch (Exception e) { Log.d("Exception", "invoke error"); } return null; } public Object invoke(Object obj, Object... args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { Log.d("ReflectionInvoke", "invoke invoke invoke"); return method.invoke(obj, args); } }其次:須要準備一個實現parcelable的對象,用來在兩個進程之間傳遞方法名、方法參數等信息。
package com.zlc.aidl; import java.io.IOException; import java.util.ArrayList; import java.util.List; import android.graphics.Bitmap; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Parcelable; public class JsonReflectionInvokParcelable implements Parcelable{ public String objectId; public String methodname; public List<String> argsClassName; public List<Object> argsVaule; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(objectId); dest.writeString(methodname); dest.writeList(argsClassName); dest.writeList(argsVaule); } public static final Parcelable.Creator<JsonReflectionInvokParcelable> CREATOR = new Parcelable.Creator<JsonReflectionInvokParcelable>() { public JsonReflectionInvokParcelable createFromParcel(Parcel in) { JsonReflectionInvokParcelable tp = new JsonReflectionInvokParcelable(); tp.objectId = in.readString(); tp.methodname = in.readString(); tp.argsClassName = new ArrayList<String>(); in.readList(tp.argsClassName, null); tp.argsVaule = new ArrayList<Object>(); in.readList(tp.argsVaule, null); return tp; } public JsonReflectionInvokParcelable[] newArray(int size) { return new JsonReflectionInvokParcelable[size]; } }; public void clean() { for (Object o : argsVaule) { try { if (o instanceof ParcelFileDescriptor) ((ParcelFileDescriptor) o).close(); else if (o instanceof Bitmap) ((Bitmap) o).recycle(); } catch (IOException e) { } } } }
服務端調用 ide
再次:服務端發送數據以前檢測而且封裝參數的類型…… public void callReflection(String json, String objId, String method, Object ...args) throws RemoteException { JsonReflectionInvokParcelable p = new JsonReflectionInvokParcelable(); p.objectId = objId; p.methodname = method; p.argsClassName = new ArrayList<String>(); p.argsVaule = new ArrayList<Object>(); Log.d(TAG, "callReflection222 json=" + json); for (int i = 0; i < args.length; i++) { Object o = args[i]; @SuppressWarnings("rawtypes") Class clazz = o.getClass(); if (clazz.isPrimitive() || o instanceof Parcelable || o instanceof String || o instanceof Integer || o instanceof Short || o instanceof Float || o instanceof Double || o instanceof Character) { p.argsClassName.add(clazz.getCanonicalName()); p.argsVaule.add(o); } else { throw new RuntimeException("args only support primitives and String"); } } callback.onReflectionCallback(p, json); Log.d(TAG, "callReflection222 end json=" + json); } ……最後:從服務端調用客戶端註冊view的某個指定方法
private final IMyAidlService.Stub mBinder = new IMyAidlService.Stub() { @Override public void registerClient(AIDLCallback cb) throws RemoteException { Log.d(TAG, "registerClient"); callback = cb; Bitmap bmp = BitmapFactory.decodeFile("/data/data/com.zlc.aidl.server/files/1.jpg"); callReflection("just for test","myImageView","setImageBitmap",bmp); cb.asBinder().linkToDeath(new DeathRecipient() { @Override public void binderDied() { // TODO Auto-generated method stub try { Log.i(TAG, "[ServiceAIDLImpl]binderDied."); } catch (Throwable e) { } } }, 0); } };
具體反射的其餘一些用途和使用方式,你們能夠去問問度娘和谷哥,這有個例子講述了大部分使用方法。 工具