使用返回类型表示一般的`MethodType`作为任何对象

时间:2014-01-25 20:28:55

标签: java java-8 methodhandle

让我的问题成为一个类:

class MyClass {
    String name() {
        return toString();
    }
}

我想创建一个MethodType的实例,它描述一个返回为“任何”对象的方法。我正在尝试以下方法:

MethodType genericTypeWithObjectReturn = 
    MethodType.methodType(Object.class, new Class[] {});

然后尝试使用

查找方法
MethodHandle mh = 
    lookup.findVirtual(MyClass.class, "name", genericTypeWithObjectReturn);

使用上面一行,我得到一个例外:

Caused by: java.lang.NoSuchMethodError: MyClass.name()Ljava/lang/Object;

我的观察是方法返回类型应该完全相同的类型;即我应该在上面的语句中使用String.class来定义MethodType。它是否正确?有没有办法让我能按照我描述的方式做到这一点,最好不要使用反射API?

3 个答案:

答案 0 :(得分:2)

因为答案仍然缺失......

MethodType必须准确。这是MethodHandles-API中的一个重点,但仅仅因为您控制转换是一些可能的优化。解决方案是使用反射来查找方法,然后使用MethodHandles #rereflect *来获取句柄。

答案 1 :(得分:0)

没有指定确切的方法类型(包括返回类型),无法使用find{Virtual,Static}方法获取方法句柄。这是JVM允许在返回类型上重载的结果,即使Java编程语言没有。从Class.getMethod的文档(强调我的):

  

在类或接口中查找匹配方法C:如果C只声明了一个具有指定名称和完全相同的形式参数类型的公共方法,那么这就是反映的方法。如果在C中找到多个这样的方法,并且这些方法中的一个具有比任何其他方法更具体的返回类型,则反映该方法; 否则其中一种方法是任意选择的

     

请注意,类中可能有多个匹配方法,因为虽然Java语言禁止类声明具有相同签名但返回类型不同的多个方法,但Java虚拟机却没有。虚拟机中增加的灵活性可用于实现各种语言功能。例如,可以使用桥接方法实现协变返回;桥方法和被覆盖的方法将具有相同的签名但返回类型不同。

因此,通过具有相同签名但不同(不是更具体)返回类型的其他方法的存在,可以使Class.getMethod无法访问JVM方法。鉴于方法句柄的目的是支持JVM上的其他语言,包括支持源代码中的返回类型重载或者生成返回类型重载的语言作为映射到JVM的一部分,这个漏洞必须通过要求来修复要指定的确切类型。 (您可以想象一个方法pow(int, int),其重载返回int,long和BigInteger,由源语言根据foo(pow(1000, 100000));中的上下文类型选择。)

除了要求所有方法都可访问的硬性要求之外,从API设计的角度来看,如果找不到所需的方法而不是默默地选择与参数兼容但不同的方法,则可以更快地失败。


如果您对Class.getMethod的查找语义感到满意,可以使用它并在返回的Method上调用MethodHandles.Lookup.unreflect

答案 2 :(得分:0)

是肯定的。你应该使用String.class来解析正确的方法类型。 我知道你不能用方法处理api来实现它,但你可以使用Reflection API。