package question3;
import java.lang.reflect.Method;
import java.util.ArrayList;
/*
* 寫一個ArrayList類的代理,其內部實現和ArrayList中完全相同的功能,
* 並可以計算每個方法運行的時間。
*
* 解題方式二
* 1.反射機制實現代理調用
* 2.實現統一的代理工廠方法來實現代理的創建
* 3.爲該方法的耗時計算實現線程安全,以精度爲納秒計算
* 4.爲目標ArrayList實現線程安全
*
* 優點:摒棄了第一種方式的大量代碼創建量
* 相對於第一種方式,可以調用ArrayList的上層
* 方法和本地方法,而不僅是上層方法
* 缺點:反射方式總歸還是會導致目標方法調用耗時多一些
* 而invoke方法的隱式類型方式,不熟悉Arraylist
* 的話很容易出錯,同時這樣的代理侷限性很明顯,
* 僅僅只支持ArrayList
*
* 注:1秒=1 000 000 000納秒 jdk api中以毫微秒錶示納秒
*/
public class ArrayListProxy_2<E>
{
@SuppressWarnings("unchecked")
public static void main(String[] args)
{
ArrayListProxy_2<String> proxy = ArrayListProxy_2.factory();
proxy.invoke("add", new Class[]{Object.class}, new Object[]{"zhangsan"});
proxy.invoke("size", null, null);
//本行如果不註釋,會拋異常,因爲沒有這個方法
//不過並不會導致程序終止
//proxy.invoke("lalalala", null, null);
proxy.invoke("get", new Class[]{int.class}, new Object[]{0});
}
/**
* 此代理的目標ArrayList,該成員只有代理類
* 可以持有,所以不應該暴露給用戶,而是私有
*/
private ArrayList<E> target = new ArrayList<E>();
/*
* 爲該代理實現工廠方法,並私有化構造方法
* 實現統一的代理創建方式
*/
private ArrayListProxy_2(){}
public static final <E> ArrayListProxy_2<E> factory()
{
return new ArrayListProxy_2<E>();
}
/**
* 本類的代理方法,用以實現ArrayList的所有方法的
* 代理調用,並統計耗時,本方法是線程安全的
*
* <p><font color=red>代理方法並不應該因爲異常而導致程序終止(退出),
* 而是應該以日誌方式記錄該異常信息,以表明該代理
* 的使用者存在顯式的錯誤</font>
*
* @param methodName 需要調用的方法名稱
* @param parameterTypes 該方法的參數類型列表
* @param parameters 該方法的參數列表
* @return 該方法的返回值;如果出現異常,並不會被拋出
* 控制檯僅以錯誤方式顯示該異常的信息,但不會
* 包括異常堆棧信息,而同時返回null
*/
public Object invoke(String methodName, Class<? extends Object>[] parameterTypes, Object[] parameters)
{
try
{
Object returnValue = null;
Method method = target.getClass().getMethod(methodName, parameterTypes);
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;
}
}
}
以反射的方式實現的定向代理
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.