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?
 
    