如何测试类中是否存在私有静态函数,而不必捕获 NoSuchMethodException



我正在创建一个实用程序函数,该函数返回给定所有部分的Method对象。其参数:

  • 返回类型 ( Class<?>
  • 包含类 ( Class<?>[]
  • 函数名称 ( String
  • 参数类数组 ( Class<?>[]

请注意,包含类参数是一个数组。这些类中只有一个必须包含该方法,但您无法知道是哪一个。除了可以显式指定的类之外,这是指定默认类的一种方式。

我的目标是按顺序搜索此数组中的每个类,如果它包含该方法,则返回其Method对象。我想这样做而不必尝试捕捉NoSuchMethodException(如本问题中所述)。由于该方法可能是私有的,因此无法使用Class.getMethods()

(它还允许私有静态,但我不确定这是否会影响这个问题。

您如何以这种方式搜索私有方法?如何进行"类中是否存在函数"测试,而不必使用NoSuchMethodException作为"错误"逻辑?

详细信息: https://www.google.com/search?q=class+contains+method+java

使用 getDeclaredMethods 返回所有方法,包括非公共方法。

for(Class<?> cls : classesToCheck) {
    for(Method m : cls.getDeclaredMethods()) {
        if(!m.getName().equals(methodName))
            continue;
        if(m.getReturnType() != returnType)
            continue;
        Class<?>[] pams = m.getParameterTypes();
        if(pams.length != pamsToCheckFor.length)
            continue;
        int i;
        for(i = 0; i < pams.length; i++) {
            if(pams[i] != pamsToCheckFor[i])
                break;
        }
        if(i == pams.length)
            return m; // or return true
    }
}
// not found

这是相当多的工作,但肯定可以完成。

请注意,如果您经常使用相同的类执行此类操作,则可能需要将 Method 对象存储在本地某处,例如 HashMap。调用 getFields/getMethods/getConstructors/etc 每次都会创建一个新数组,并复制其中的所有对象。仅仅找到一件事就是一种相对昂贵的操作。

作为琐事,有一个名为sun.reflect.ReflectionFactory的类可以制作这些防御性副本。

java.lang.Class的源代码还显示,像getMethodgetDeclaredMethod这样的方法与上面的代码片段非常相似,只是它们可能不会制作副本。因此,作为性能优化的一部分,复制是值得权衡的。如果不存在的方法被认为是不太可能的结果,除非您像我建议的那样缓存方法,否则搜索数组实际上可能不会更快。

考虑搜索类似 java.lang.String 的类。这是一个相当大的类,调用getDeclaredMethods将创建相当多的对象。

我喜欢

@Radiodef的答案,但它缺少一些东西:getDeclaredClass只返回在Class本身中声明的方法,而不是在其超类中声明的方法。由于超类方法通常也被视为类的方法,因此您也需要搜索它们。

其次,在指定返回类型时,通常希望找到一个返回方法,该方法返回可以分配给该返回类型的内容,而不是确切的返回类型。在 Java 中,重写超类方法的方法返回超类的返回类型的子类是合法的。即超类有Number myNumber(),那么子类可能有@Override Integer myNumber()

如果你也考虑到这一点,你会得到这个代码:

public static Method findMethod(Class<?> returnType, Collection<? extends Class<?>> containingClasses, String functionName, Class<?>[] parameters) {
    for (Class<?> containingClass : containingClasses) {
        Method m = findMethodInClass(returnType, containingClass, functionName, parameters);
        if (m != null)
            return m;
    }
    return null;
}
private static Method findMethodInClass(Class<?> returnType, Class<?> containingClass, String functionName, Class<?>[] parameters) {
    for (Method m : containingClass.getDeclaredMethods()) {
        if (checkMethod(m, returnType, functionName, parameters))
            return m;
    }
    if (containingClass.getSuperclass() != null)
        return findMethodInClass(returnType, containingClass.getSuperclass(), functionName, parameters);
    else
        return null;
}
private static boolean checkMethod(Method method, Class<?> returnType, String functionName, Class<?>[] parameters) {
    if (!method.getName().equals(functionName))
        return false;
    // Also allow overridden classes that return a subtype of the requested type
    if (!returnType.isAssignableFrom(method.getReturnType()))
        return false;
    Class<?>[] actualParameters = method.getParameterTypes();
    if (actualParameters.length != parameters.length)
        return false;
    for (int i = 0; i < actualParameters.length; i++) {
        if (actualParameters[i] != parameters[i])
            return false;
    }
    return true;
}
public static void main(String[] args) {
    System.out.println(findMethod(Integer.TYPE, Collections.singleton(Integer.class), "intValue", new Class<?>[0]));
    System.out.println(findMethod(String.class, Collections.singleton(Random.class), "toString", new Class<?>[0]));
}

不过,我建议不要出于任何原因在sun.*包中使用任何类;包括sun.reflect.ReflectionFactory。这些类不是受支持的 Java 公共接口的一部分,可以随时更改或删除。

请参阅:Sun 发生了什么。

相关内容

  • 没有找到相关文章

最新更新