如何获取Java 8方法引用的MethodInfo?

请看下面的代码:

Method methodInfo = MyClass.class.getMethod("myMethod"); 

这个工作,但方法名称是作为一个string传递,所以即使myMethod不存在,这将编译。

另一方面,Java 8引入了一个方法引用特性。 在编译时检查。 有可能使用此function获取方法信息?

 printMethodName(MyClass::myMethod); 

完整的例子:

 @FunctionalInterface private interface Action { void invoke(); } private static class MyClass { public static void myMethod() { } } private static void printMethodName(Action action) { } public static void main(String[] args) throws NoSuchMethodException { // This works, but method name is passed as a string, so this will compile // even if myMethod does not exist Method methodInfo = MyClass.class.getMethod("myMethod"); // Here we pass reference to a method. It is somehow possible to // obtain java.lang.reflect.Method for myMethod inside printMethodName? printMethodName(MyClass::myMethod); } 

换句话说,我想有一个代码,这是相当于下面的C#代码:

  private static class InnerClass { public static void MyMethod() { Console.WriteLine("Hello"); } } static void PrintMethodName(Action action) { // Can I get java.lang.reflect.Method in the same way? MethodInfo methodInfo = action.GetMethodInfo(); } static void Main() { PrintMethodName(InnerClass.MyMethod); } 

不,没有可靠的,支持的方式来做到这一点。 您将一个方法引用分配给一个function接口的实例,但该实例由LambdaMetaFactory ,并且无法钻取该实例以查找最初绑定的方法。

Java中的Lambdas和方法引用与C#中的代表完全不同。 对于一些有趣的背景,请阅读invokedynamic

在这里的其他答案和评论表明,目前可能有一些额外的工作检索绑定的方法,但要确保你了解的警告。

看起来好像有可能通过使用代理logging哪个方法被调用。

https://stackoverflow.com/a/22745127/3478229

在我的情况下,我正在寻找一种在unit testing中摆脱这种情况的方法:

 Point p = getAPoint(); assertEquals(p.getX(), 4, "x"); assertEquals(p.getY(), 6, "x"); 

正如你可以看到有人正在testing方法getAPoint并检查坐标是否如预期的一样,但是在每个断言的描述中被复制,并且与被检查的内容不同步。 最好只写一次。

从@ddan的想法,我使用Mockito构build了一个代理解决scheme:

 private<T> void assertPropertyEqual(final T object, final Function<T, ?> getter, final Object expected) { final String methodName = getMethodName(object.getClass(), getter); assertEquals(getter.apply(object), expected, methodName); } @SuppressWarnings("unchecked") private<T> String getMethodName(final Class<?> clazz, final Function<T, ?> getter) { final Method[] method = new Method[1]; getter.apply((T)Mockito.mock(clazz, Mockito.withSettings().invocationListeners(methodInvocationReport -> { method[0] = ((InvocationOnMock) methodInvocationReport.getInvocation()).getMethod(); }))); return method[0].getName(); } 

不,我可以简单地使用

 assertPropertyEqual(p, Point::getX, 4); assertPropertyEqual(p, Point::getY, 6); 

并且assert的描述保证与代码同步。

下行:

  • 会比上面慢一点
  • 需要Mockito工作
  • 除了上面的用例之外,对于其他任何东西都不起作

然而,它确实显示了如何做到这一点。

虽然我自己没有尝试过,但我认为答案是“否”,因为方法引用在语义上与lambda相同。

如果你可以使接口Action扩展Serializable ,那么从另一个问题的答案似乎提供了一个解决scheme(至less在一些编译器和运行时)。

尝试这个

 Thread.currentThread().getStackTrace()[2].getMethodName(); 

我们已经发布了可以用来捕获方法名称的小型库de.cronn:reflection-util 。

例:

 class MyClass { public void myMethod() { } } String methodName = ClassUtils.getVoidMethodName(MyClass.class, MyClass::myMethod); System.out.println(methodName); // prints "myMethod" 

实现细节:使用ByteBuddy创buildMyClass的Proxy子类,并捕获方法的调用以检索其名称。 ClassUtilscaching信息,使得我们不需要为每个调用创build一个新的代理。

请注意,这种方法不适用于静态方法。