我需要找到一種方法,以這樣的方式來緩存方法(java.lang.reflect.Method
),每當我調用一個函數與類(Class
)方法名(String
)和參數(T[]
)功能將返回緩存的方法(如果存在)或找到該方法,將其添加到緩存並返回。重寫的hashCode equals方法
我想用HashMap緩存,以便我能找到在O方法(1),但問題是,我需要使用isAssignableFrom
當我覆蓋了equals方法:
public class A1 extends AParent {}
public class A2 extends AParent {}
public class AParent {}
public class Temp{
public void testFunc(AParent a){}
}
這是類我在HashMap中使用的鍵:
import java.util.Arrays;
class MethodAbs{
Class c;
String methodName;
Class<?>[] argsTypes;
public MethodAbs(Class c, String methodName, Class<?>[] argsTypes){
this.c = c;
this.methodName = methodName;
this.argsTypes = argsTypes;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MethodAbs methodAbs = (MethodAbs) o;
if (c != null ? !c.equals(methodAbs.c) : methodAbs.c != null) return false;
if (methodName != null ? !methodName.equals(methodAbs.methodName) : methodAbs.methodName != null)
return false;
return isArgsTypesEq(argsTypes, methodAbs.argsTypes);
}
//a method is equals to the one cached if the arguments types
// can be cast to the ones that are saved on the map,
// i.e the ones on the method declaration
private boolean isArgsTypesEq(Class<?>[] at1, Class<?>[] at2){
boolean res = at1.length == at2.length;
for(int i = 0; i<at1.length && res; i++){
if(!at1[i].isAssignableFrom(at2[i])) res = false;
}
return res;
}
//default implementation (not working properly!)
@Override
public int hashCode() {
int result = c != null ? c.hashCode() : 0;
result = 31 * result + (methodName != null ? methodName.hashCode() : 0);
result = 31 * result + Arrays.hashCode(argsTypes);
return result;
}
}
我使用的緩存類
class Run{
public Map<MethodAbs, Method> map = new HashMap<>();
public<T> Method myFunc(Class c, String methodName, T[] args){
MethodAbs ma = new MethodAbs(c, methodName, getTypes(args));
if(map.containsKey(ma)){
return map.get(ma);
}
else{
for(Method method: c.getMethods()){
MethodAbs currMethodAbs = new MethodAbs(c, method.getName(), method.getParameterTypes());
if(!map.containsKey(currMethodAbs))
map.put(currMethodAbs, method);
if(currMethodAbs.equals(ma)) break;
}
}
return map.get(ma);
}
private<T> Class<?>[] getTypes(T[] args) {
Class<?>[] types = new Class<?>[args.length];
for(int i = 0; i< args.length; i++){
types[i] = args[i].getClass();
}
return types;
}
}
而且主營:
public static void main(String[] args){
Run r = new Run();
Object [] arr = new Object[1];
arr[0] = new A1();
r.myFunc(Temp.class, "testFunc", arr);
arr[0] = new A2();
r.myFunc(Temp.class, "testFunc", arr);
}
在該方案中調用r.myFunc首次上面後,地圖上看起來是這樣的:
MethodAbs(Temp.class, "testFunc", [AParent.class])
在第二時間map.containsKey
將返回false(因爲AParent.hashCode!= A2.hashCode),但他們是equals
。
- 在示例中所示的層次結構不一定會看起來像(例如A2可以是AParent的孫)
我知道可以使用類和方法名作爲關鍵字和值將是我需要迭代和比較平等的方法列表,但我試圖找到一個更好的方法...
我同意破損的對稱性問題,但是我不能使用getDecleredMethod,因爲它期望接收方法的確切對象類型。在上面的例子中用Class A1調用它會拋出一個異常,因爲它正在尋找類AParent。任何想法如何解決這個問題? –