package question3;
import java.lang.reflect.Method;
/*
* 寫一個ArrayList類的代理,其內部實現和ArrayList中完全相同的功能,
* 並可以計算每個方法運行的時間。
*
* 解題方式三
* 1.反射機制實現代理調用
* 2.實現統一的代理工廠方法來實現代理的創建
* 3.爲該方法的耗時計算實現線程安全,以精度爲納秒計算
* 4.爲目標invoke實現線程安全
* 5.實現任意代理,不在侷限於ArrayList
* 6.實現參數的動態識別,更精簡的參數列表
*
* 優點:相對於第二種方式,將可以支持代理類型的多樣化
* 但代理代碼方面仍然死板,對於不同功能的代理
* 扔需要編寫額外的代理類,但相對於第1 2種,
* 仍然可以節省大量開發時間
*
* 缺點:參數類型動態識別方面仍然存在缺陷,至少來說也不是
* 那麼廢柴,還是看亮點吧。。。
*
* 注:1秒=1 000 000 000納秒 jdk api中以毫微秒錶示納秒
*/
public class ArrayListProxy_3
{
/**
* 此代理的目標對象,該成員只有代理類
* 可以持有,所以不應該暴露給用戶,而是私有
*/
private Object target;
/**
* 構造函數私有化,該代理僅可通過 {@link #factory(String)}
* 取得實例
*/
private ArrayListProxy_3(String targetType) throws ClassNotFoundException,
InstantiationException, IllegalAccessException
{
target = Class.forName(targetType).newInstance();
System.out.println("create the target instance from "+target.getClass().getName());
}
/**
* 本類的工廠方法
*
* @param targetType 目標類型,該類型應該是完整的<br>
* for example java.util.ArrayList
*/
public static final ArrayListProxy_3 factory(String targetType) throws ClassNotFoundException,
InstantiationException, IllegalAccessException
{
return new ArrayListProxy_3(targetType);
}
/**
* 本類的代理方法,用以實現ArrayList的所有方法的
* 代理調用,並統計耗時,本方法是線程安全的
*
* <p><font color=red>代理方法並不應該因爲異常而導致程序終止(退出),
* 而是應該以日誌方式記錄該異常信息,以表明該代理
* 的使用者存在顯式的錯誤</font>
*
* @param methodName 需要調用的方法名稱
* @param parameterTypes 該方法的參數類型列表
* @param parameters 該方法的參數列表
* @return 該方法的返回值;如果出現異常,並不會被拋出
* 控制檯僅以錯誤方式顯示該異常的信息,但不會
* 包括異常堆棧信息,而同時返回null
*/
public Object invoke(String methodName, Object... parameters)
{
try
{
Object returnValue = null;
Method method = target.getClass().getMethod(methodName, getParameterTypes(parameters));
long taken = 0;
/*
* 同步實現的目標方法調用以及耗時統計
*/
synchronized (target)
{
if(null != methodName)
{
taken = System.nanoTime();
returnValue = method.invoke(target, parameters);
taken = System.nanoTime() - taken;
}
}
/*
* 控制檯輸出目標方法調用的詳細信息,包括報名,類名,方法名
* 以及實參的參數列表(傳入的實際參數列表),數組不在此列。。。
* 並輸出返回值和耗時
*/
System.out.print(target.getClass().getName()+"."+method.getName()+"(");
if(null != parameters)
for (int i = 0; i < parameters.length; i++)
{
System.out.print(parameters[i]);
if(i != parameters.length - 1)
System.out.print(", ");
}
System.out.println(") return "+returnValue+" times taken by "+taken+" ns");
/*
* 將返回值返回給使用者
*/
return returnValue;
}
catch (Exception e)
{
/*
* 木有用e.printStackTrace(),運行時異常會導致程序掛掉
* 所以僅以錯誤方式輸出,這裏應該是需要寫進log裏面,log4j
* 找不到了。。。(┬_┬)
*
*/
System.out.flush();
System.err.println(e.getClass().getName()+":"+e.getMessage());
System.err.flush();
return null;
}
}
/**
* 根據參數自動識別類型
*
* <p>該方法對於範型實例還可以,因爲都提供最基本的
* Object元素訪問,其他的實例會發生一些強轉異常
*
* <p>本方法是爲了實現invoke方法的便捷使用,但會
* 額外消耗調用時間,降低效率
*/
@SuppressWarnings("unchecked")
public Class<? extends Object>[] getParameterTypes(Object[] parameters) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException
{
if(parameters != null)
{
Class[] class_array = new Class[parameters.length];
for (int i = 0; i < class_array.length; i++)
{
//如果該參數的類型是基本類型,那麼保持原類型
if(parameters[i].getClass().isPrimitive())
class_array[i] = parameters[i].getClass();
//如果爲包裝類型則轉換成基本類型
//該處理是針對的自動裝箱功能
else if(parameters[i] instanceof Number)
class_array[i] = (Class) parameters[i].getClass().getField("TYPE").get(parameters[i]);
//否則以Object類型傳入
else
class_array[i] = Object.class;
//其實還差一步是處理添加集合的方式
//這裏的添加集合會走參數爲Object的方法
}
return class_array;
}
else
return null;
}
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException
{
/*
* 測試ArrayList的部分
*/
ArrayListProxy_3 proxy;
proxy = ArrayListProxy_3.factory("java.util.ArrayList");
proxy.invoke("add", "qqq");
proxy.invoke("size", null);
proxy.invoke("get", 0);
proxy.invoke("remove", 0);
System.out.println("==============================================>");
/*
* 測試Linkedlist的部分
*/
proxy = ArrayListProxy_3.factory("java.util.LinkedList");
proxy.invoke("add", "aaa");
proxy.invoke("size", null);
proxy.invoke("get", 0);
proxy.invoke("remove", 0);
System.out.println("==============================================>");
/*
* 測試treemap
*/
proxy = ArrayListProxy_3.factory("java.util.TreeMap");
proxy.invoke("put", "asd","efg");
proxy.invoke("remove","asd");
proxy.invoke("get", "asd");
proxy.invoke("size", null);
System.out.println("==============================================>");
}
}
以反射的方式實現的任意代理 可以代理本地方法
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.