I hope to find the declaring class of a method in Android. The basic idea is to find if the target method is declared in a class. If not, I will recursively find the target method in its super classes. For a specific reason, efficiency matters. So I have two implementations and I compared their performance differences.
Version 1: use the API Class.getDeclaredMethod
to check if a method exists in a class. If not, NoSuchMethodException
will be thrown.
public Class getDeclaringClass1(Class cls, String mtdName, Class[] paraTypes) {
Class declaringCls = null;
try {
declaringCls = cls.getDeclaredMethod(mtdName, paraTypes).getDeclaringClass();
} catch (NoSuchMethodException | SecurityException e) {
Class supr = cls.getSuperclass();
if(supr != null) declaringCls = getDeclaringClass1(supr, mtdName, paraTypes);
}
return declaringCls;
}
Version 2: Manually check if a method is declared in a class using Class.getDeclaredMethods
. We will match each method one by one with the method name and parameter types.
public Class getDeclaringClass2(Class cls, String mtdName, Class[] paraTypes) {
Class declaringCls = null;
Method[] methods = cls.getDeclaredMethods();
boolean containsMtd = false;
for(Method method: methods) {
if(method.getName().equals(mtdName)) {
boolean allEqual = true;
for(int i=0; i< method.getParameterTypes().length; i++) {
if(! method.getParameterTypes()[i].equals(paraTypes[i])) {
allEqual = false;
break;
}
}
if(allEqual) {
containsMtd = true;
declaringCls = cls;
break;
}
}
}
if(! containsMtd) {
Class supr = cls.getSuperclass();
if(supr != null) declaringCls = getDeclaringClass2(supr, mtdName, paraTypes);
}
return declaringCls;
}
I made some interesting observations when testing the efficiency of these two versions. Basically I created several empty classes C
, CC
, CCC
, CCCC
. Their relationships are
CC extends C
CCC extends CC
CCCC extends CCC
All these classes does not declare any methods and I use the toString
method as the target method. I testing two getDeclaringClass
with a loop of 10000 times:
start = System.currentTimeMillis();
for(long i=0; i<10000; i++) {
getDeclaringClass(cls, "toString", new Class[0]).getName()); // getDeclaringClass will be set to version 1 or 2
}
end = System.currentTimeMillis();
System.out.println((end - start) + "ms");
Here are the results:
cls | Version 1 | Version 2 |
---|---|---|
C | 1168ms | 1632ms |
CC | 2599ms | 1397ms |
CCC | 3495ms | 1680ms |
CCCC | 4908ms | 1559ms |
We can see that version 1's performance drops significantly when we have more levels of class inheritance. But version 2's performance does not change a lot.
So what makes the difference between version 1 and 2? What makes version 1 so slow?
Aucun commentaire:
Enregistrer un commentaire