4

让以下成为我的问题中的一个类:

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?

4

3 回答 3

2

因为仍然缺少答案...

MethodType 必须准确。这是 MethodHandles-API 的一大痛点,但仅因为您控制了转换,才有可能进行一些优化。解决方法是使用反射找到方法,然后使用 MethodHandles#unreflect* 获取句柄。

于 2014-03-11T10:33:10.317 回答
0

There's no way to use the find{Virtual,Static} methods to get method handles without specifying the exact method type, including the return type. This is a consequence of the JVM allowing overloading on return type, even though the Java programming language does not. From the documentation for Class.getMethod (emphasis mine):

To find a matching method in a class or interface C: If C declares exactly one public method with the specified name and exactly the same formal parameter types, that is the method reflected. If more than one such method is found in C, and one of these methods has a return type that is more specific than any of the others, that method is reflected; otherwise one of the methods is chosen arbitrarily.

Note that there may be more than one matching method in a class because while the Java language forbids a class to declare multiple methods with the same signature but different return types, the Java virtual machine does not. This increased flexibility in the virtual machine can be used to implement various language features. For example, covariant returns can be implemented with bridge methods; the bridge method and the method being overridden would have the same signature but different return types.

Thus JVM methods can be made inaccessible to Class.getMethod by the presence of other methods with the same signature but different (not-more-specific) return types. Given that the purpose of method handles is to support other languages on the JVM, including languages that either support overloading on return type in the source or that generate return type overloads as part of mapping to the JVM, this hole had to be fixed by requiring the exact type to be specified. (You could imagine a method pow(int, int) with overloads returning int, long, and BigInteger, selected by the source language based on the context type in foo(pow(1000, 100000));.)

Apart from that hard requirement to make all methods accessible, it's arguably better from an API design standpoint to fail fast if the desired method is not found rather than silently select an argument-compatible but different method.


If you're happy with the lookup semantics of Class.getMethod, you can use it and call MethodHandles.Lookup.unreflect on the returned Method.

于 2014-06-29T05:58:17.497 回答
0

是的。您应该使用 String.class 来解析正确的方法类型。我知道你不能用方法句柄 api 来实现它,但你可以使用反射 API。

于 2015-07-18T15:14:37.727 回答