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.