java反射機制在項目中的運用

定義:
    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);
			
		}
	};

    具體反射的其餘一些用途和使用方式,你們能夠去問問度娘和谷哥,這有個例子講述了大部分使用方法。 工具


最後附上反射使用實例的源碼,圖片本身下載一張存放到/data/data/com.zlc.aidl.server/files/目錄下,若是沒有files目錄,可經過代碼建立或者經過linux命令建立。
相關文章
相關標籤/搜索