Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 是否有Class.getMethod()反射和自动装箱的解决方案?_Java_Reflection - Fatal编程技术网

Java 是否有Class.getMethod()反射和自动装箱的解决方案?

Java 是否有Class.getMethod()反射和自动装箱的解决方案?,java,reflection,Java,Reflection,我想用 Class.getMethod(String name, Class... parameterTypes) 要找到我需要使用给定参数调用的方法,但显然如Java中所述,其中不包括自动装箱。因此,如果我的反射类有一个带有(String,int)签名的方法,那么仍然会得到一个NoSuchMethodException,其中{String.class,Integer.class}数组作为参数 有什么解决办法吗?我所能想到的唯一方法是,对基本类型和非基本类型的每一种排列调用getMethod(

我想用

Class.getMethod(String name, Class... parameterTypes)
要找到我需要使用给定参数调用的方法,但显然如Java中所述,其中不包括自动装箱。因此,如果我的反射类有一个带有(String,int)签名的方法,那么仍然会得到一个NoSuchMethodException,其中{String.class,Integer.class}数组作为参数

有什么解决办法吗?我所能想到的唯一方法是,对基本类型和非基本类型的每一种排列调用getMethod(),而我实际上并不想这样做

编辑:更清楚地说:我很了解基元类型类,但我不知道它们如何帮助解决我的问题。我的parameterTypes数组来自某个地方,我知道它只返回非基本类型。我不能假设接口将仅使用基元类型声明,这正是我的问题:

public interface TestInterface()
{
    public void doTest(Integer i1, int i2, double d3, Double d);
}

Class<?>[] classes = { Integer.class, Integer.class, Double.class, Double.class }
// Due to autoboxing I should become the doTest method here, but it doesn't work
TestInterface.class.getMethod("doTest", classes);
公共接口测试接口()
{
公共void doTest(整数i1、整数i2、双d3、双d);
}
类[]类={Integer.Class,Integer.Class,Double.Class,Double.Class}
//由于自动装箱,我应该成为这里最受欢迎的方法,但它不起作用
TestInterface.class.getMethod(“doTest”,类);

Integer.class表示整数对象类型。Integer.TYPE表示int基元类型。这行吗?

是的,您需要使用
Integer.TYPE
或(等效地)
int.class


更新:“我的parameterTypes数组来自某个地方,我知道它只会返回非基本类型。”那么,这就是“某个地方”的问题。如果他们没有给你他们想要的方法的正确签名,那么你将如何找到它?如果有两个重载方法,它们的不同之处仅在于其中一个采用原语,另一个采用包装器类,该怎么办?那么它选择哪一个呢?我的意思是,如果你真的没有选择,那么我想你可以循环所有的方法,寻找一个具有正确名称的方法,手动检查所有的参数类型,看它们是否正确,或者是原始的等价物。

反射方法查找不如编译器的复杂。我理解你为什么需要那样的东西。假设在运行时,您有一个方法名和一个对象数组作为参数,并且希望反射根据参数的类型为您提供确切的方法,但它比这更复杂。例如:

void f(Integer i){..}
void f(int i){...}
当参数为整型时,可以选择哪一种?更棘手的是:

void f(Integer i, List l){...}
void f(Object o, LinkedList l){...}
编译器有一套基于静态信息选择“最具体方法”的规则;如果无法确定,它将立即提醒您


您必须模拟编译器并编写算法以找出“最具体的方法”。(哦,考虑到自动装箱,几乎忘记了这一点!)

目前唯一的答案是编写代码来模拟Java编译器的类型提升规则,这是一种反思性地选择最合适的方法。自动装箱和取消装箱只是编译器知道的类型升级的示例

为什么Java反射API还没有做到这一点?我能想到很多原因

  • 在Java1.5之前,
    getMethod
    类和朋友不知道如何(例如)将
    int
    提升到
    float
    。如果1.5之前没有必要,为什么现在

  • 添加此类内容将使反射方法调用更加缓慢

  • 自动装箱和取消装箱可能与非反射方法调用混淆。添加反射只会增加更多的混乱

  • 升级规则的运行时实现将添加一类需要映射到异常并由用户代码诊断的新运行时错误案例。这些问题将特别棘手。例如,它必须处理一个不明确的方法调用的反射等价物

  • 向后兼容性的首要要求意味着Sun必须将其作为新方法实现。他们无法更改当前方法的行为,因为这可能会破坏成千上万客户的现有应用程序

最后一点与OP的用例(如上所述)特别相关。OP说他的代码不知道是否期望(例如)在目标类上使用
int
Integer
参数的方法。假设编写目标类的人提供了两个重载。。。语义有微妙的(或不恰当的)不同?不管你做什么,总会有这样的情况:OP的代码选择了客户端不期望的重载。糟糕


依我看,OP的代码最好能强加一些简单的API规则,说明什么时候使用原语和包装器是正确的。

正如@Stephen C提到的,你唯一的希望就是自己进行搜索。他所有的警告都成立,但我认为只要打电话的人知道这些警告,稍微灵活一点就可以覆盖大部分的哥特卡。。。而不是让你的来电者总是非常具体

对于实际执行类似操作的代码,您可以在此处查看:

findMethod()调用是入口点,但它将(在一些缓存等之后)委托给此方法:

private Method searchForMethod( String name, Class[] parms ) {
    Method[] methods = type.getMethods();
    for( int i = 0; i < methods.length; i++ ) {
        // Has to be named the same of course.
        if( !methods[i].getName().equals( name ) )
            continue;

        Class[] types = methods[i].getParameterTypes();

        // Does it have the same number of arguments that we're looking for.
        if( types.length != parms.length )
            continue;

        // Check for type compatibility
        if( InspectionUtils.areTypesCompatible( types, parms ) )
            return methods[i];
        }
    return null;
}
私有方法searchFormMethod(字符串名称,类[]parms){
Method[]methods=type.getMethods();
for(int i=0;i    for( int i = 0; i < targets.length; i++ ) {
        if( sources[i] == null )
            continue;

        if( !translateFromPrimitive( targets[i] ).isAssignableFrom( sources[i] ) )
            return false;
        }
    return( true );
}
for(Method m:getDeclaredMethods())
  for(Class c:m.getParameterTypes() && Class desired:desiredMethodArgTypes)
    if(c.isAssignableFrom(desired))
      //matches
    if(c.isPrimitive() && c==desired.getDeclaredField("TYPE").get(desiredObject))
      //matches